[
  {
    "path": ".gitignore",
    "content": "# build products...\n*.py[co]\n# Mac OS X stuff...\n.DS_Store\n# test output\n*.retry\n# JetBrains project dir\n.idea\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "\n\n# Contributing to ansible-for-nsxt\n\nThe ansible-for-nsxt project team welcomes contributions from the community. Before you start working with ansible-for-nsxt, please read our [Developer Certificate of Origin](https://cla.vmware.com/dco). All contributions to this repository must be signed as described on that page. Your signature certifies that you wrote the patch or have the right to pass it on as an open-source patch.\n\n## Community\n\n## Getting Started\n\n## Contribution Flow\n\nThis is a rough outline of what a contributor's workflow looks like:\n\n- Create a topic branch from where you want to base your work\n- Make commits of logical units\n- Make sure your commit messages are in the proper format (see below)\n- Push your changes to a topic branch in your fork of the repository\n- Submit a pull request\n\nExample:\n\n``` shell\ngit remote add upstream https://github.com/vmware/ansible-for-nsxt.git\ngit checkout -b my-new-feature master\ngit commit -a\ngit push origin my-new-feature\n```\n\n### Staying In Sync With Upstream\n\nWhen your branch gets out of sync with the vmware/master branch, use the following to update:\n\n``` shell\ngit checkout my-new-feature\ngit fetch -a\ngit pull --rebase upstream master\ngit push --force-with-lease origin my-new-feature\n```\n\n### Updating pull requests\n\nIf your PR fails to pass CI or needs changes based on code review, you'll most likely want to squash these changes into\nexisting commits.\n\nIf your pull request contains a single commit or your changes are related to the most recent commit, you can simply\namend the commit.\n\n``` shell\ngit add .\ngit commit --amend\ngit push --force-with-lease origin my-new-feature\n```\n\nIf you need to squash changes into an earlier commit, you can use:\n\n``` shell\ngit add .\ngit commit --fixup <commit>\ngit rebase -i --autosquash master\ngit push --force-with-lease origin my-new-feature\n```\n\nBe sure to add a comment to the PR indicating your new changes are ready to review, as GitHub does not generate a\nnotification when you git push.\n\n### Code Style\n\n### Formatting Commit Messages\n\nWe follow the conventions on [How to Write a Git Commit Message](http://chris.beams.io/posts/git-commit/).\n\nBe sure to include any related GitHub issue references in the commit message.  See\n[GFM syntax](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown) for referencing issues\nand commits.\n\n## Reporting Bugs and Creating Issues\n\nWhen opening a new issue, try to roughly follow the commit message format conventions above.\n\n## Repository Structure\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "ansible-for-nsxt\r\n\r\nCopyright (c) 2018 VMware, Inc.  All rights reserved\t\t\t\t\r\nSPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\r\n\r\nThis code is Dual Licensed BSD 2-Clause or GPLv3\r\n\r\n===============================================================================\r\n\r\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\r\n\r\n1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\r\n\r\n2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\r\n\r\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n\r\n===============================================================================\r\n\r\n                    GNU GENERAL PUBLIC LICENSE\r\n                       Version 3, 29 June 2007\r\n\r\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\r\n Everyone is permitted to copy and distribute verbatim copies\r\n of this license document, but changing it is not allowed.\r\n\r\n                            Preamble\r\n\r\n  The GNU General Public License is a free, copyleft license for\r\nsoftware and other kinds of works.\r\n\r\n  The licenses for most software and other practical works are designed\r\nto take away your freedom to share and change the works.  By contrast,\r\nthe GNU General Public License is intended to guarantee your freedom to\r\nshare and change all versions of a program--to make sure it remains free\r\nsoftware for all its users.  We, the Free Software Foundation, use the\r\nGNU General Public License for most of our software; it applies also to\r\nany other work released this way by its authors.  You can apply it to\r\nyour programs, too.\r\n\r\n  When we speak of free software, we are referring to freedom, not\r\nprice.  Our General Public Licenses are designed to make sure that you\r\nhave the freedom to distribute copies of free software (and charge for\r\nthem if you wish), that you receive source code or can get it if you\r\nwant it, that you can change the software or use pieces of it in new\r\nfree programs, and that you know you can do these things.\r\n\r\n  To protect your rights, we need to prevent others from denying you\r\nthese rights or asking you to surrender the rights.  Therefore, you have\r\ncertain responsibilities if you distribute copies of the software, or if\r\nyou modify it: responsibilities to respect the freedom of others.\r\n\r\n  For example, if you distribute copies of such a program, whether\r\ngratis or for a fee, you must pass on to the recipients the same\r\nfreedoms that you received.  You must make sure that they, too, receive\r\nor can get the source code.  And you must show them these terms so they\r\nknow their rights.\r\n\r\n  Developers that use the GNU GPL protect your rights with two steps:\r\n(1) assert copyright on the software, and (2) offer you this License\r\ngiving you legal permission to copy, distribute and/or modify it.\r\n\r\n  For the developers' and authors' protection, the GPL clearly explains\r\nthat there is no warranty for this free software.  For both users' and\r\nauthors' sake, the GPL requires that modified versions be marked as\r\nchanged, so that their problems will not be attributed erroneously to\r\nauthors of previous versions.\r\n\r\n  Some devices are designed to deny users access to install or run\r\nmodified versions of the software inside them, although the manufacturer\r\ncan do so.  This is fundamentally incompatible with the aim of\r\nprotecting users' freedom to change the software.  The systematic\r\npattern of such abuse occurs in the area of products for individuals to\r\nuse, which is precisely where it is most unacceptable.  Therefore, we\r\nhave designed this version of the GPL to prohibit the practice for those\r\nproducts.  If such problems arise substantially in other domains, we\r\nstand ready to extend this provision to those domains in future versions\r\nof the GPL, as needed to protect the freedom of users.\r\n\r\n  Finally, every program is threatened constantly by software patents.\r\nStates should not allow patents to restrict development and use of\r\nsoftware on general-purpose computers, but in those that do, we wish to\r\navoid the special danger that patents applied to a free program could\r\nmake it effectively proprietary.  To prevent this, the GPL assures that\r\npatents cannot be used to render the program non-free.\r\n\r\n  The precise terms and conditions for copying, distribution and\r\nmodification follow.\r\n\r\n                       TERMS AND CONDITIONS\r\n\r\n  0. Definitions.\r\n\r\n  \"This License\" refers to version 3 of the GNU General Public License.\r\n\r\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\r\nworks, such as semiconductor masks.\r\n\r\n  \"The Program\" refers to any copyrightable work licensed under this\r\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\r\n\"recipients\" may be individuals or organizations.\r\n\r\n  To \"modify\" a work means to copy from or adapt all or part of the work\r\nin a fashion requiring copyright permission, other than the making of an\r\nexact copy.  The resulting work is called a \"modified version\" of the\r\nearlier work or a work \"based on\" the earlier work.\r\n\r\n  A \"covered work\" means either the unmodified Program or a work based\r\non the Program.\r\n\r\n  To \"propagate\" a work means to do anything with it that, without\r\npermission, would make you directly or secondarily liable for\r\ninfringement under applicable copyright law, except executing it on a\r\ncomputer or modifying a private copy.  Propagation includes copying,\r\ndistribution (with or without modification), making available to the\r\npublic, and in some countries other activities as well.\r\n\r\n  To \"convey\" a work means any kind of propagation that enables other\r\nparties to make or receive copies.  Mere interaction with a user through\r\na computer network, with no transfer of a copy, is not conveying.\r\n\r\n  An interactive user interface displays \"Appropriate Legal Notices\"\r\nto the extent that it includes a convenient and prominently visible\r\nfeature that (1) displays an appropriate copyright notice, and (2)\r\ntells the user that there is no warranty for the work (except to the\r\nextent that warranties are provided), that licensees may convey the\r\nwork under this License, and how to view a copy of this License.  If\r\nthe interface presents a list of user commands or options, such as a\r\nmenu, a prominent item in the list meets this criterion.\r\n\r\n  1. Source Code.\r\n\r\n  The \"source code\" for a work means the preferred form of the work\r\nfor making modifications to it.  \"Object code\" means any non-source\r\nform of a work.\r\n\r\n  A \"Standard Interface\" means an interface that either is an official\r\nstandard defined by a recognized standards body, or, in the case of\r\ninterfaces specified for a particular programming language, one that\r\nis widely used among developers working in that language.\r\n\r\n  The \"System Libraries\" of an executable work include anything, other\r\nthan the work as a whole, that (a) is included in the normal form of\r\npackaging a Major Component, but which is not part of that Major\r\nComponent, and (b) serves only to enable use of the work with that\r\nMajor Component, or to implement a Standard Interface for which an\r\nimplementation is available to the public in source code form.  A\r\n\"Major Component\", in this context, means a major essential component\r\n(kernel, window system, and so on) of the specific operating system\r\n(if any) on which the executable work runs, or a compiler used to\r\nproduce the work, or an object code interpreter used to run it.\r\n\r\n  The \"Corresponding Source\" for a work in object code form means all\r\nthe source code needed to generate, install, and (for an executable\r\nwork) run the object code and to modify the work, including scripts to\r\ncontrol those activities.  However, it does not include the work's\r\nSystem Libraries, or general-purpose tools or generally available free\r\nprograms which are used unmodified in performing those activities but\r\nwhich are not part of the work.  For example, Corresponding Source\r\nincludes interface definition files associated with source files for\r\nthe work, and the source code for shared libraries and dynamically\r\nlinked subprograms that the work is specifically designed to require,\r\nsuch as by intimate data communication or control flow between those\r\nsubprograms and other parts of the work.\r\n\r\n  The Corresponding Source need not include anything that users\r\ncan regenerate automatically from other parts of the Corresponding\r\nSource.\r\n\r\n  The Corresponding Source for a work in source code form is that\r\nsame work.\r\n\r\n  2. Basic Permissions.\r\n\r\n  All rights granted under this License are granted for the term of\r\ncopyright on the Program, and are irrevocable provided the stated\r\nconditions are met.  This License explicitly affirms your unlimited\r\npermission to run the unmodified Program.  The output from running a\r\ncovered work is covered by this License only if the output, given its\r\ncontent, constitutes a covered work.  This License acknowledges your\r\nrights of fair use or other equivalent, as provided by copyright law.\r\n\r\n  You may make, run and propagate covered works that you do not\r\nconvey, without conditions so long as your license otherwise remains\r\nin force.  You may convey covered works to others for the sole purpose\r\nof having them make modifications exclusively for you, or provide you\r\nwith facilities for running those works, provided that you comply with\r\nthe terms of this License in conveying all material for which you do\r\nnot control copyright.  Those thus making or running the covered works\r\nfor you must do so exclusively on your behalf, under your direction\r\nand control, on terms that prohibit them from making any copies of\r\nyour copyrighted material outside their relationship with you.\r\n\r\n  Conveying under any other circumstances is permitted solely under\r\nthe conditions stated below.  Sublicensing is not allowed; section 10\r\nmakes it unnecessary.\r\n\r\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\r\n\r\n  No covered work shall be deemed part of an effective technological\r\nmeasure under any applicable law fulfilling obligations under article\r\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\r\nsimilar laws prohibiting or restricting circumvention of such\r\nmeasures.\r\n\r\n  When you convey a covered work, you waive any legal power to forbid\r\ncircumvention of technological measures to the extent such circumvention\r\nis effected by exercising rights under this License with respect to\r\nthe covered work, and you disclaim any intention to limit operation or\r\nmodification of the work as a means of enforcing, against the work's\r\nusers, your or third parties' legal rights to forbid circumvention of\r\ntechnological measures.\r\n\r\n  4. Conveying Verbatim Copies.\r\n\r\n  You may convey verbatim copies of the Program's source code as you\r\nreceive it, in any medium, provided that you conspicuously and\r\nappropriately publish on each copy an appropriate copyright notice;\r\nkeep intact all notices stating that this License and any\r\nnon-permissive terms added in accord with section 7 apply to the code;\r\nkeep intact all notices of the absence of any warranty; and give all\r\nrecipients a copy of this License along with the Program.\r\n\r\n  You may charge any price or no price for each copy that you convey,\r\nand you may offer support or warranty protection for a fee.\r\n\r\n  5. Conveying Modified Source Versions.\r\n\r\n  You may convey a work based on the Program, or the modifications to\r\nproduce it from the Program, in the form of source code under the\r\nterms of section 4, provided that you also meet all of these conditions:\r\n\r\n    a) The work must carry prominent notices stating that you modified\r\n    it, and giving a relevant date.\r\n\r\n    b) The work must carry prominent notices stating that it is\r\n    released under this License and any conditions added under section\r\n    7.  This requirement modifies the requirement in section 4 to\r\n    \"keep intact all notices\".\r\n\r\n    c) You must license the entire work, as a whole, under this\r\n    License to anyone who comes into possession of a copy.  This\r\n    License will therefore apply, along with any applicable section 7\r\n    additional terms, to the whole of the work, and all its parts,\r\n    regardless of how they are packaged.  This License gives no\r\n    permission to license the work in any other way, but it does not\r\n    invalidate such permission if you have separately received it.\r\n\r\n    d) If the work has interactive user interfaces, each must display\r\n    Appropriate Legal Notices; however, if the Program has interactive\r\n    interfaces that do not display Appropriate Legal Notices, your\r\n    work need not make them do so.\r\n\r\n  A compilation of a covered work with other separate and independent\r\nworks, which are not by their nature extensions of the covered work,\r\nand which are not combined with it such as to form a larger program,\r\nin or on a volume of a storage or distribution medium, is called an\r\n\"aggregate\" if the compilation and its resulting copyright are not\r\nused to limit the access or legal rights of the compilation's users\r\nbeyond what the individual works permit.  Inclusion of a covered work\r\nin an aggregate does not cause this License to apply to the other\r\nparts of the aggregate.\r\n\r\n  6. Conveying Non-Source Forms.\r\n\r\n  You may convey a covered work in object code form under the terms\r\nof sections 4 and 5, provided that you also convey the\r\nmachine-readable Corresponding Source under the terms of this License,\r\nin one of these ways:\r\n\r\n    a) Convey the object code in, or embodied in, a physical product\r\n    (including a physical distribution medium), accompanied by the\r\n    Corresponding Source fixed on a durable physical medium\r\n    customarily used for software interchange.\r\n\r\n    b) Convey the object code in, or embodied in, a physical product\r\n    (including a physical distribution medium), accompanied by a\r\n    written offer, valid for at least three years and valid for as\r\n    long as you offer spare parts or customer support for that product\r\n    model, to give anyone who possesses the object code either (1) a\r\n    copy of the Corresponding Source for all the software in the\r\n    product that is covered by this License, on a durable physical\r\n    medium customarily used for software interchange, for a price no\r\n    more than your reasonable cost of physically performing this\r\n    conveying of source, or (2) access to copy the\r\n    Corresponding Source from a network server at no charge.\r\n\r\n    c) Convey individual copies of the object code with a copy of the\r\n    written offer to provide the Corresponding Source.  This\r\n    alternative is allowed only occasionally and noncommercially, and\r\n    only if you received the object code with such an offer, in accord\r\n    with subsection 6b.\r\n\r\n    d) Convey the object code by offering access from a designated\r\n    place (gratis or for a charge), and offer equivalent access to the\r\n    Corresponding Source in the same way through the same place at no\r\n    further charge.  You need not require recipients to copy the\r\n    Corresponding Source along with the object code.  If the place to\r\n    copy the object code is a network server, the Corresponding Source\r\n    may be on a different server (operated by you or a third party)\r\n    that supports equivalent copying facilities, provided you maintain\r\n    clear directions next to the object code saying where to find the\r\n    Corresponding Source.  Regardless of what server hosts the\r\n    Corresponding Source, you remain obligated to ensure that it is\r\n    available for as long as needed to satisfy these requirements.\r\n\r\n    e) Convey the object code using peer-to-peer transmission, provided\r\n    you inform other peers where the object code and Corresponding\r\n    Source of the work are being offered to the general public at no\r\n    charge under subsection 6d.\r\n\r\n  A separable portion of the object code, whose source code is excluded\r\nfrom the Corresponding Source as a System Library, need not be\r\nincluded in conveying the object code work.\r\n\r\n  A \"User Product\" is either (1) a \"consumer product\", which means any\r\ntangible personal property which is normally used for personal, family,\r\nor household purposes, or (2) anything designed or sold for incorporation\r\ninto a dwelling.  In determining whether a product is a consumer product,\r\ndoubtful cases shall be resolved in favor of coverage.  For a particular\r\nproduct received by a particular user, \"normally used\" refers to a\r\ntypical or common use of that class of product, regardless of the status\r\nof the particular user or of the way in which the particular user\r\nactually uses, or expects or is expected to use, the product.  A product\r\nis a consumer product regardless of whether the product has substantial\r\ncommercial, industrial or non-consumer uses, unless such uses represent\r\nthe only significant mode of use of the product.\r\n\r\n  \"Installation Information\" for a User Product means any methods,\r\nprocedures, authorization keys, or other information required to install\r\nand execute modified versions of a covered work in that User Product from\r\na modified version of its Corresponding Source.  The information must\r\nsuffice to ensure that the continued functioning of the modified object\r\ncode is in no case prevented or interfered with solely because\r\nmodification has been made.\r\n\r\n  If you convey an object code work under this section in, or with, or\r\nspecifically for use in, a User Product, and the conveying occurs as\r\npart of a transaction in which the right of possession and use of the\r\nUser Product is transferred to the recipient in perpetuity or for a\r\nfixed term (regardless of how the transaction is characterized), the\r\nCorresponding Source conveyed under this section must be accompanied\r\nby the Installation Information.  But this requirement does not apply\r\nif neither you nor any third party retains the ability to install\r\nmodified object code on the User Product (for example, the work has\r\nbeen installed in ROM).\r\n\r\n  The requirement to provide Installation Information does not include a\r\nrequirement to continue to provide support service, warranty, or updates\r\nfor a work that has been modified or installed by the recipient, or for\r\nthe User Product in which it has been modified or installed.  Access to a\r\nnetwork may be denied when the modification itself materially and\r\nadversely affects the operation of the network or violates the rules and\r\nprotocols for communication across the network.\r\n\r\n  Corresponding Source conveyed, and Installation Information provided,\r\nin accord with this section must be in a format that is publicly\r\ndocumented (and with an implementation available to the public in\r\nsource code form), and must require no special password or key for\r\nunpacking, reading or copying.\r\n\r\n  7. Additional Terms.\r\n\r\n  \"Additional permissions\" are terms that supplement the terms of this\r\nLicense by making exceptions from one or more of its conditions.\r\nAdditional permissions that are applicable to the entire Program shall\r\nbe treated as though they were included in this License, to the extent\r\nthat they are valid under applicable law.  If additional permissions\r\napply only to part of the Program, that part may be used separately\r\nunder those permissions, but the entire Program remains governed by\r\nthis License without regard to the additional permissions.\r\n\r\n  When you convey a copy of a covered work, you may at your option\r\nremove any additional permissions from that copy, or from any part of\r\nit.  (Additional permissions may be written to require their own\r\nremoval in certain cases when you modify the work.)  You may place\r\nadditional permissions on material, added by you to a covered work,\r\nfor which you have or can give appropriate copyright permission.\r\n\r\n  Notwithstanding any other provision of this License, for material you\r\nadd to a covered work, you may (if authorized by the copyright holders of\r\nthat material) supplement the terms of this License with terms:\r\n\r\n    a) Disclaiming warranty or limiting liability differently from the\r\n    terms of sections 15 and 16 of this License; or\r\n\r\n    b) Requiring preservation of specified reasonable legal notices or\r\n    author attributions in that material or in the Appropriate Legal\r\n    Notices displayed by works containing it; or\r\n\r\n    c) Prohibiting misrepresentation of the origin of that material, or\r\n    requiring that modified versions of such material be marked in\r\n    reasonable ways as different from the original version; or\r\n\r\n    d) Limiting the use for publicity purposes of names of licensors or\r\n    authors of the material; or\r\n\r\n    e) Declining to grant rights under trademark law for use of some\r\n    trade names, trademarks, or service marks; or\r\n\r\n    f) Requiring indemnification of licensors and authors of that\r\n    material by anyone who conveys the material (or modified versions of\r\n    it) with contractual assumptions of liability to the recipient, for\r\n    any liability that these contractual assumptions directly impose on\r\n    those licensors and authors.\r\n\r\n  All other non-permissive additional terms are considered \"further\r\nrestrictions\" within the meaning of section 10.  If the Program as you\r\nreceived it, or any part of it, contains a notice stating that it is\r\ngoverned by this License along with a term that is a further\r\nrestriction, you may remove that term.  If a license document contains\r\na further restriction but permits relicensing or conveying under this\r\nLicense, you may add to a covered work material governed by the terms\r\nof that license document, provided that the further restriction does\r\nnot survive such relicensing or conveying.\r\n\r\n  If you add terms to a covered work in accord with this section, you\r\nmust place, in the relevant source files, a statement of the\r\nadditional terms that apply to those files, or a notice indicating\r\nwhere to find the applicable terms.\r\n\r\n  Additional terms, permissive or non-permissive, may be stated in the\r\nform of a separately written license, or stated as exceptions;\r\nthe above requirements apply either way.\r\n\r\n  8. Termination.\r\n\r\n  You may not propagate or modify a covered work except as expressly\r\nprovided under this License.  Any attempt otherwise to propagate or\r\nmodify it is void, and will automatically terminate your rights under\r\nthis License (including any patent licenses granted under the third\r\nparagraph of section 11).\r\n\r\n  However, if you cease all violation of this License, then your\r\nlicense from a particular copyright holder is reinstated (a)\r\nprovisionally, unless and until the copyright holder explicitly and\r\nfinally terminates your license, and (b) permanently, if the copyright\r\nholder fails to notify you of the violation by some reasonable means\r\nprior to 60 days after the cessation.\r\n\r\n  Moreover, your license from a particular copyright holder is\r\nreinstated permanently if the copyright holder notifies you of the\r\nviolation by some reasonable means, this is the first time you have\r\nreceived notice of violation of this License (for any work) from that\r\ncopyright holder, and you cure the violation prior to 30 days after\r\nyour receipt of the notice.\r\n\r\n  Termination of your rights under this section does not terminate the\r\nlicenses of parties who have received copies or rights from you under\r\nthis License.  If your rights have been terminated and not permanently\r\nreinstated, you do not qualify to receive new licenses for the same\r\nmaterial under section 10.\r\n\r\n  9. Acceptance Not Required for Having Copies.\r\n\r\n  You are not required to accept this License in order to receive or\r\nrun a copy of the Program.  Ancillary propagation of a covered work\r\noccurring solely as a consequence of using peer-to-peer transmission\r\nto receive a copy likewise does not require acceptance.  However,\r\nnothing other than this License grants you permission to propagate or\r\nmodify any covered work.  These actions infringe copyright if you do\r\nnot accept this License.  Therefore, by modifying or propagating a\r\ncovered work, you indicate your acceptance of this License to do so.\r\n\r\n  10. Automatic Licensing of Downstream Recipients.\r\n\r\n  Each time you convey a covered work, the recipient automatically\r\nreceives a license from the original licensors, to run, modify and\r\npropagate that work, subject to this License.  You are not responsible\r\nfor enforcing compliance by third parties with this License.\r\n\r\n  An \"entity transaction\" is a transaction transferring control of an\r\norganization, or substantially all assets of one, or subdividing an\r\norganization, or merging organizations.  If propagation of a covered\r\nwork results from an entity transaction, each party to that\r\ntransaction who receives a copy of the work also receives whatever\r\nlicenses to the work the party's predecessor in interest had or could\r\ngive under the previous paragraph, plus a right to possession of the\r\nCorresponding Source of the work from the predecessor in interest, if\r\nthe predecessor has it or can get it with reasonable efforts.\r\n\r\n  You may not impose any further restrictions on the exercise of the\r\nrights granted or affirmed under this License.  For example, you may\r\nnot impose a license fee, royalty, or other charge for exercise of\r\nrights granted under this License, and you may not initiate litigation\r\n(including a cross-claim or counterclaim in a lawsuit) alleging that\r\nany patent claim is infringed by making, using, selling, offering for\r\nsale, or importing the Program or any portion of it.\r\n\r\n  11. Patents.\r\n\r\n  A \"contributor\" is a copyright holder who authorizes use under this\r\nLicense of the Program or a work on which the Program is based.  The\r\nwork thus licensed is called the contributor's \"contributor version\".\r\n\r\n  A contributor's \"essential patent claims\" are all patent claims\r\nowned or controlled by the contributor, whether already acquired or\r\nhereafter acquired, that would be infringed by some manner, permitted\r\nby this License, of making, using, or selling its contributor version,\r\nbut do not include claims that would be infringed only as a\r\nconsequence of further modification of the contributor version.  For\r\npurposes of this definition, \"control\" includes the right to grant\r\npatent sublicenses in a manner consistent with the requirements of\r\nthis License.\r\n\r\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\r\npatent license under the contributor's essential patent claims, to\r\nmake, use, sell, offer for sale, import and otherwise run, modify and\r\npropagate the contents of its contributor version.\r\n\r\n  In the following three paragraphs, a \"patent license\" is any express\r\nagreement or commitment, however denominated, not to enforce a patent\r\n(such as an express permission to practice a patent or covenant not to\r\nsue for patent infringement).  To \"grant\" such a patent license to a\r\nparty means to make such an agreement or commitment not to enforce a\r\npatent against the party.\r\n\r\n  If you convey a covered work, knowingly relying on a patent license,\r\nand the Corresponding Source of the work is not available for anyone\r\nto copy, free of charge and under the terms of this License, through a\r\npublicly available network server or other readily accessible means,\r\nthen you must either (1) cause the Corresponding Source to be so\r\navailable, or (2) arrange to deprive yourself of the benefit of the\r\npatent license for this particular work, or (3) arrange, in a manner\r\nconsistent with the requirements of this License, to extend the patent\r\nlicense to downstream recipients.  \"Knowingly relying\" means you have\r\nactual knowledge that, but for the patent license, your conveying the\r\ncovered work in a country, or your recipient's use of the covered work\r\nin a country, would infringe one or more identifiable patents in that\r\ncountry that you have reason to believe are valid.\r\n\r\n  If, pursuant to or in connection with a single transaction or\r\narrangement, you convey, or propagate by procuring conveyance of, a\r\ncovered work, and grant a patent license to some of the parties\r\nreceiving the covered work authorizing them to use, propagate, modify\r\nor convey a specific copy of the covered work, then the patent license\r\nyou grant is automatically extended to all recipients of the covered\r\nwork and works based on it.\r\n\r\n  A patent license is \"discriminatory\" if it does not include within\r\nthe scope of its coverage, prohibits the exercise of, or is\r\nconditioned on the non-exercise of one or more of the rights that are\r\nspecifically granted under this License.  You may not convey a covered\r\nwork if you are a party to an arrangement with a third party that is\r\nin the business of distributing software, under which you make payment\r\nto the third party based on the extent of your activity of conveying\r\nthe work, and under which the third party grants, to any of the\r\nparties who would receive the covered work from you, a discriminatory\r\npatent license (a) in connection with copies of the covered work\r\nconveyed by you (or copies made from those copies), or (b) primarily\r\nfor and in connection with specific products or compilations that\r\ncontain the covered work, unless you entered into that arrangement,\r\nor that patent license was granted, prior to 28 March 2007.\r\n\r\n  Nothing in this License shall be construed as excluding or limiting\r\nany implied license or other defenses to infringement that may\r\notherwise be available to you under applicable patent law.\r\n\r\n  12. No Surrender of Others' Freedom.\r\n\r\n  If conditions are imposed on you (whether by court order, agreement or\r\notherwise) that contradict the conditions of this License, they do not\r\nexcuse you from the conditions of this License.  If you cannot convey a\r\ncovered work so as to satisfy simultaneously your obligations under this\r\nLicense and any other pertinent obligations, then as a consequence you may\r\nnot convey it at all.  For example, if you agree to terms that obligate you\r\nto collect a royalty for further conveying from those to whom you convey\r\nthe Program, the only way you could satisfy both those terms and this\r\nLicense would be to refrain entirely from conveying the Program.\r\n\r\n  13. Use with the GNU Affero General Public License.\r\n\r\n  Notwithstanding any other provision of this License, you have\r\npermission to link or combine any covered work with a work licensed\r\nunder version 3 of the GNU Affero General Public License into a single\r\ncombined work, and to convey the resulting work.  The terms of this\r\nLicense will continue to apply to the part which is the covered work,\r\nbut the special requirements of the GNU Affero General Public License,\r\nsection 13, concerning interaction through a network will apply to the\r\ncombination as such.\r\n\r\n  14. Revised Versions of this License.\r\n\r\n  The Free Software Foundation may publish revised and/or new versions of\r\nthe GNU General Public License from time to time.  Such new versions will\r\nbe similar in spirit to the present version, but may differ in detail to\r\naddress new problems or concerns.\r\n\r\n  Each version is given a distinguishing version number.  If the\r\nProgram specifies that a certain numbered version of the GNU General\r\nPublic License \"or any later version\" applies to it, you have the\r\noption of following the terms and conditions either of that numbered\r\nversion or of any later version published by the Free Software\r\nFoundation.  If the Program does not specify a version number of the\r\nGNU General Public License, you may choose any version ever published\r\nby the Free Software Foundation.\r\n\r\n  If the Program specifies that a proxy can decide which future\r\nversions of the GNU General Public License can be used, that proxy's\r\npublic statement of acceptance of a version permanently authorizes you\r\nto choose that version for the Program.\r\n\r\n  Later license versions may give you additional or different\r\npermissions.  However, no additional obligations are imposed on any\r\nauthor or copyright holder as a result of your choosing to follow a\r\nlater version.\r\n\r\n  15. Disclaimer of Warranty.\r\n\r\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\r\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\r\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\r\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\r\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\r\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\r\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\r\n\r\n  16. Limitation of Liability.\r\n\r\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\r\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\r\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\r\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\r\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\r\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\r\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\r\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\r\nSUCH DAMAGES.\r\n\r\n  17. Interpretation of Sections 15 and 16.\r\n\r\n  If the disclaimer of warranty and limitation of liability provided\r\nabove cannot be given local legal effect according to their terms,\r\nreviewing courts shall apply local law that most closely approximates\r\nan absolute waiver of all civil liability in connection with the\r\nProgram, unless a warranty or assumption of liability accompanies a\r\ncopy of the Program in return for a fee.\r\n\r\n                     END OF TERMS AND CONDITIONS\r\n\r\n            How to Apply These Terms to Your New Programs\r\n\r\n  If you develop a new program, and you want it to be of the greatest\r\npossible use to the public, the best way to achieve this is to make it\r\nfree software which everyone can redistribute and change under these terms.\r\n\r\n  To do so, attach the following notices to the program.  It is safest\r\nto attach them to the start of each source file to most effectively\r\nstate the exclusion of warranty; and each file should have at least\r\nthe \"copyright\" line and a pointer to where the full notice is found.\r\n\r\n    <one line to give the program's name and a brief idea of what it does.>\r\n    Copyright (C) <year>  <name of author>\r\n\r\n    This program is free software: you can redistribute it and/or modify\r\n    it under the terms of the GNU General Public License as published by\r\n    the Free Software Foundation, either version 3 of the License, or\r\n    (at your option) any later version.\r\n\r\n    This program is distributed in the hope that it will be useful,\r\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n    GNU General Public License for more details.\r\n\r\n    You should have received a copy of the GNU General Public License\r\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\r\n\r\nAlso add information on how to contact you by electronic and paper mail.\r\n\r\n  If the program does terminal interaction, make it output a short\r\nnotice like this when it starts in an interactive mode:\r\n\r\n    <program>  Copyright (C) <year>  <name of author>\r\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\r\n    This is free software, and you are welcome to redistribute it\r\n    under certain conditions; type `show c' for details.\r\n\r\nThe hypothetical commands `show w' and `show c' should show the appropriate\r\nparts of the General Public License.  Of course, your program's commands\r\nmight be different; for a GUI interface, you would use an \"about box\".\r\n\r\n  You should also get your employer (if you work as a programmer) or school,\r\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\r\nFor more information on this, and how to apply and follow the GNU GPL, see\r\n<https://www.gnu.org/licenses/>.\r\n\r\n  The GNU General Public License does not permit incorporating your program\r\ninto proprietary programs.  If your program is a subroutine library, you\r\nmay consider it more useful to permit linking proprietary applications with\r\nthe library.  If this is what you want to do, use the GNU Lesser General\r\nPublic License instead of this License.  But first, please read\r\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\r\n"
  },
  {
    "path": "README.md",
    "content": "# Ansible for NSX-T\n\n## Overview\nThis repository contains NSX-T Ansible Modules, which one can use with\nAnsible to work with [VMware NSX-T Data Center][vmware-nsxt].\n\n[vmware-nsxt]: https://www.vmware.com/products/nsx.html\n\nFor general information about Ansible, visit the [GitHub project page][an-github].\n\n[an-github]: https://github.com/ansible/ansible\n\nThese modules are maintained by [VMware](https://www.vmware.com/).\n\nDocumentation on the NSX platform can be found at the [NSX-T Documentation page](https://docs.vmware.com/en/VMware-NSX-T/index.html)\n\n## NSX Compatibility\n\nThe following versions of NSX are supported:\n\n * NSX-T 4.2\n * NSX-T 4.1\n * NSX-T 4.0\n * NSX-T 3.2\n * NSX-T 3.1\n * NSX-T 3.0\n * NSX-T 2.5.1\n\n## Prerequisites\n\nUsing Ansible-for-nsxt requires the following packages to be installated. Installation steps differ based on the platform (Mac/iOS, Ubuntu, Debian, CentOS, RHEL etc). Please follow the links below to pick the right platform.\n\n* Ansible >= 2.10.x [Ansible Installation Documentation](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html)\n* Python3 >= 3.6.x [Python Documentation](https://www.python.org/downloads/)\n* pip3 >= 9.x Python Installation [PIP installation](https://pip.pypa.io/en/stable/installing/)\n* PyVmOmi - Python library for vCenter api. Installation via pip: [pyVmomi installation](https://pypi.org/project/pyvmomi/)\n* OVF Tools >= 4.4.x - Ovftool is used for ovf deployment [OVFTool Download and Installation](https://code.vmware.com/web/tool/4.4.0/ovf)\n\n## Installation\n\nansible-for-nsxt modules are distributed as Ansible Galaxy collection. Please use the following command to install it\n\n```\nansible-galaxy collection install git+https://github.com/vmware/ansible-for-nsxt\n```\n\nSpecify latest supported release branch\n\n```\nansible-galaxy collection install git+https://github.com/vmware/ansible-for-nsxt.git,v3.2.0\n```\n\n## Usage\n\nOnce installed, the modules can be directly run with ansible-playbook. For example, you can run:\n\n```\nansible-playbook  test_logical_switches.yml\n```\n\nThe modules require you to provide details about how to authenticate with NSX-T.\n\n\n### Using modules in the tests folder\n\nThere are complete workflow example modules in the tests/playbooks folder. To use them, edit the corresponding vars file if rqeuired. Then run using ansible-playbook. For example,\n\n```\nansible-playbook 01_create_t0_gateway.yml\n```\n\n\n### Supported NSX Objects/Workflows\nThe modules in this repository are focused on enabling automation of installation workflows of NSX-T. We have modules that support the legacy MP and new Policy API.\n\n#### MP API\nMP API modules can be used to configure an NSX resource with one-to-one mapping.\n\n### Branch Information\nThis repository has different branches with each branch providing support for upto a specific NSX-T release. Below is the list:\n* Master: Latest code, under development\n* v3.2.0: NSX-T 3.2.x and below\n* v3.0.1: NSX-T 3.1.x and below\n* v3.0.0: NSX-T 3.0.x and below\n* v1.1.0: NSX-T 2.4, NSX-T 2.5\n* v1.0.0: NSX-T 2.3\n\n##### Deployment and installation modules\n\n* nsxt_deploy_ova\n* nsxt_licenses\n* nsxt_manager_status\n* nsxt_licenses_facts\n* nsxt_edge_clusters\n* nsxt_edge_clusters_facts\n* nsxt_fabric_compute_managers\n* nsxt_fabric_compute_managers_facts\n* nsxt_ip_pools\n* nsxt_ip_pools_facts\n* nsxt_uplink_profiles\n* nsxt_uplink_profiles_facts\n* nsxt_transport_zones\n* nsxt_transport_zones_facts\n* nsxt_transport_nodes\n* nsxt_transport_nodes_facts\n* nsxt_transport_node_collections\n* nsxt_transport_node_collections_facts\n* nsxt_transport_node_profiles\n* nsxt_transport_node_profiles_facts\n* nsxt_controller_manager_auto_deployment\n\n###### Logical networking modules\n* nsxt_logical_ports\n* nsxt_logical_ports_facts\n* nsxt_logical_routers\n* nsxt_logical_routers_facts\n* nsxt_logical_router_ports\n* nsxt_logical_router_ports_facts\n* nsxt_logical_router_static_routes\n* nsxt_logical_switches\n* nsxt_logical_switches_facts\n* nsxt_ip_blocks\n* nsxt_ip_blocks_facts\n\n#### Policy API\nPolicy API modules are aggregated such that logical constructs related to an NSX resource can be configured using a single playbook. They can be identified with prefix *nsxt_policy_*. The below list outlines the supported modules and the resources that can be configured through a module.\n\nNote that the Policy modules are supported only for NSX-T 3.0 and above.\n\n1. Tier-0 Gateway (nsxt_policy_tier0)\n   1. Tier-0 Locale Services\n   2. Tier-0 Static Routes\n   3. Tier-0 Interface\n   4. Tier-0 BGP\n   5. Tier-0 BGP Neighbors\n   6. Tier-0 VRF\n   7. Tier-0 BFD Peers\n2. Tier-1 Gateway (nsxt_policy_tier1)\n   1. Tier-1 Locale Services\n   2. Tier-1 Static Routes\n   3. Tier-1 Interface\n3. Segment (nsxt_policy_segment)\n   1. Segment Port\n4. Policy Group (nsxt_policy_group)\n5. Security Policy and Firewall rules (nsxt_policy_security_policy)\n6. IP Pools (nsxt_policy_ip_pool)\n   1. IP Address Pool Block Subnet\n   2. IP Address Pool Static Subnet\n7. IP Blocks (nsxt_policy_ip_block)\n8. BFD Profile (nsxt_policy_bfd_profile)\n9. VM Tags (nsxt_vm_tags)\n10. Gateway Policy (nsxt_policy_gateway_policy)\n11. L2 Bridge Endpoint Profile (nsxt_policy_l2_bridge_ep_profile)\n\nNote that to add a new modules in Policy API, it's base class name should be added in the BASE_RESOURCES in module_utils/nsxt_base_resource.py\n\n## Build & Run\n\n### Install PyVmOmi\n```\npip install --upgrade pyvmomi pyvim requests ssl\n```\n### Download and Install Ovf tool 4.3 - [Ovftool](https://my.vmware.com/web/vmware/details?downloadGroup=OVFTOOL430&productId=742)\n(Note: Using ovftool version 4.0/4.1 causes OVA/OVF deployment failure with Error: cURL error: SSL connect error\\nCompleted with errors\\n)\n\n### Authentication\n\n#### Using MP API\nAnsible-for-nsxt supports two types of authentication using MP API.\n1. Basic server authentication\n2. Certificate based authentication\n\n##### Basic server authentication\nIn basic server authentication, client has to explicitly provide NSX username and password for the NSX manager. The credentials have to be listed in ansible-playbook.\n\n##### Certificate based authentication\nIn certificate based authentication, client has to register their certificates to NSX manager using nsxt_certificates task. After registering the certificates, client has to create its own principal identity on NSX manager using nsxt_principal_identities taks.\nThe process of certificate registration and creation of principal identity has to be done using basic server authentication. Use test_certificates.yml and test_principal_identities.yml to match the values according to the client's environment.\n```\nansible-playbook test_certificates.yml -vvv\nansible-playbook test_principal_identities -vvv\n```\nThe path of the .p12 file i.e the file containing public and private key has to be set to an environment variable named NSX_MANAGER_CERT_PATH. \n**Note:** Make sure NSX_MANAGER_CERT_PATH is set in the same remote host, where modules would be executed. \n\n###### Generating certificates?\nFollowing commands can be used in order to generate certificates.\n```\nopenssl req -newkey rsa:2048 -extensions usr_cert -nodes -keyout nsx_certificate.key -x509 -days 365 -out nsx_certificate.crt -subj \"/C=US/ST=California/L=PaloAlto/O=VMware/CN=certauth-test\" -sha256\n\nopenssl pkcs12 -export -out nsx_certificate.pfx -inkey nsx_certificate.key -in nsx_certificate.crt\n\nopenssl pkcs12 -in nsx_certificate.pfx -out nsx_certificate.p12 -nodes\n```\n\nThe nsx_certificate.crt file generated as output from the above command contains the public key certificate.\nthe file nsx_certificate.p12 file contains the public and private key generated. The path of nsx_certificate.p12 file has to be set in the environment variable NSX_MANAGER_CERT_PATH.\n\nNote: usr_cert tells OpenSSL to generate a client certificate. This must be defined in openssl.cnf.\n\n#### Validate CA in MP API\n\nTo validate ceritificate authority (CA), set NSX_MANAGER_CA_PATH environment variable on Ansible control node pointing to CA certificate of NSX manager and pass validate_certs as ``True`` in ansible playbook.\n\n#### Using Policy API\nAll the Policy API based Ansible Modules provide the following authentication mechanisms:\n\n##### Basic Authentication\nThis is the same as in MP API. It can be used by specifying the following fields in the playbook:\n1. **username**: The username to authenticate with the NSX manager\n2. **password**: The password to authenticate with the NSX manager\n\nFor example:\n```yaml\n- hosts: localhost\n  tasks:\n    - name: Update Tier0\n      nsxt_policy_tier0:\n        hostname: \"default\"\n        username: admin\n        password: my-password\n        validate_certs: False\n        display_name: test-tier0-1\n        state: present\n```\n\n##### Prinicipal Identity\nThere are 2 ways to consume the Principal Identity certificates.\n\n###### Using Environment variable\nThis is same as explained in the previous section: **Certificate based authentication**\n\n###### Specifying in the playbook\nBy specifying the following fields in the playbook:\n1. **nsx_cert_path**: Path to the certificate created for the Principal Identity using which the CRUD operations should be performed. If the certificate is a .p12 file, only this attribute is required. Otherwise, *nsx_key_path* is also required.\n2. **nsx_key_path**: Path to the certificate key created for the Principal Identity using which the CRUD operations should be performed\n\nFor example:\n```yaml\n- hosts: localhost\n  tasks:\n    - name: Update Tier0\n      nsxt_policy_tier0:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: False\n        display_name: test-tier0-1\n        state: present\n```\n\n##### vIDM\nWhen NSX-T is configured to use VMware Identity Manager (vIDM) for authentication, you can supply an Authorization header with an authentication type of *Remote*. The header content should consist of a base64-encoded string containing the username@domain and password separated by a single colon (\":\") character, as specified in RFC 1945 section 11.1.\n\nFor example, to authenticate a request using the credentials of user jsmith@example.com with password Sk2LkPM!, include the following key:value pair under **request_headers** in the playbook::\n- Authorization: 'Remote anNtaXRoQGV4YW1wbGUuY29tOlNrMkxrUE0h'\n\nFor example:\n```yaml\n- hosts: localhost\n  tasks:\n    - name: Update Tier0\n      nsxt_policy_tier0:\n        hostname: \"default\"\n        request_headers:\n          Authorization: 'Remote anNtaXRoQGV4YW1wbGUuY29tOlNrMkxrUE0h'\n        validate_certs: False\n        display_name: test-tier0-1\n        state: present\n```\n\n##### SSL Verification\nYou can use the flag *validate_certs* to perform SSL verification. You can also specify the path to a CA bundle using the paratemer *ca_path* in the playbook.\n\nFor example:\n```yaml\n- hosts: localhost\n  tasks:\n    - name: Update Tier0\n      nsxt_policy_tier0:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        display_name: test-tier0-1\n        state: present\n```\n\n# Contributing\n\nThe ansible-for-nsxt project team welcomes contributions from the community. Before you start working with ansible-for-nsxt, please read our [Developer Certificate of Origin](https://cla.vmware.com/dco). All contributions to this repository must be signed as described on that page. Your signature certifies that you wrote the patch or have the right to pass it on as an open-source patch. For more detailed information, refer to [CONTRIBUTING.md](CONTRIBUTING.md).\n\nPlease open a Pull-Request against the Master branch.\n\n# Support\n\nReleased NSX-T Ansible modules are fully supported by VMware. The released modules are available in the specific numbered release branches:\n* v3.2.0\n* v3.0.1\n* v3.0.0\n* v1.1.0\n* v1.0.0\n\nThey are also available for download from VMware's download page.\n\nThe *master* branch contains the latest development code which is community supported.\n\nFor bugs and feature requests, please open a Github Issue and label it appropriately.\n\n\n# License\nCopyright (c) 2020 VMware, Inc.  All rights reserved\n\nThe NSX-T Ansible modules in this repository are available under [BSD-2 license or GPLv3](LICENSE.txt) applies to all parts of the ansible-for-nsxt.\nYou may not use them except in compliance with the License.\n"
  },
  {
    "path": "galaxy.yml",
    "content": "namespace: vmware\n\nname: ansible_for_nsxt\n\nversion: 1.0.0\n\nreadme: README.md\n\nauthors:\n- Gautam Verma @ggverma (https://vmware.slack.com/archives/CTE293BSS)\n- Rahul Raghuvanshi @r-raghu (https://vmware.slack.com/archives/CTE293BSS)\n\ndescription: Ansible Modules for NSX-t\n\nlicense:\n- GPL-3.0-only\n- BSD-2-Clause-FreeBSD\n\nlicense_file: LICENSE.txt \n\ntags: [vmware, ansible, nsxt]\n\ndependencies: {}\n\nrepository: https://github.com/vmware/ansible-for-nsxt\n\ndocumentation: https://github.com/vmware/ansible-for-nsxt\n\nhomepage: https://github.com/vmware/ansible-for-nsxt\n\nissues: https://github.com/vmware/ansible-for-nsxt/issues\n\nbuild_ignore: []\n"
  },
  {
    "path": "meta/runtime.yml",
    "content": "requires_ansible: \">=2.9\"\n"
  },
  {
    "path": "plugins/doc_fragments/vmware_nsxt.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2021 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\nclass ModuleDocFragment(object):\n\n    # VMware NSX-T documentation fragment\n    DOCUMENTATION = \"\"\"\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        type: str\n    password:\n        description:\n            - The password to authenticate with the NSX manager.\n            - Must be specified if username is specified\n        type: str\n    ca_path:\n        description: Path to the CA bundle to be used to verify host's SSL\n                     certificate\n        type: str\n    nsx_cert_path:\n        description: Path to the certificate created for the Principal\n                     Identity using which the CRUD operations should be\n                     performed\n        type: str\n    nsx_key_path:\n        description:\n            - Path to the certificate key created for the Principal Identity\n              using which the CRUD operations should be performed\n            - Must be specified if nsx_cert_path is specified\n        type: str\n    request_headers:\n        description: HTTP request headers to be sent to the host while making\n                     any request\n        type: dict\n    display_name:\n        description:\n            - Display name.\n            - If resource ID is not specified, display_name will be used as ID.\n        required: false\n        type: str\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'.\n                    'present' is used to create or update resource.\n                    'absent' is used to delete resource.\"\n        required: true\n    validate_certs:\n        description: Enable server certificate verification.\n        type: bool\n        default: False\n    tags:\n        description: Opaque identifiers meaningful to the API user.\n        type: dict\n        suboptions:\n            scope:\n                description: Tag scope.\n                required: true\n                type: str\n            tag:\n                description: Tag value.\n                required: true\n                type: str\n    create_or_update_subresource_first:\n        type: bool\n        default: false\n        description:\n            - Can be used to create subresources first.\n            - Can be specified for each subresource.\n    delete_subresource_first:\n        type: bool\n        default: true\n        description:\n            - Can be used to delete subresources first.\n            - Can be specified for each subresource.\n    achieve_subresource_state_if_del_parent:\n        type: bool\n        default: false\n        description:\n            - Can be used to achieve the state of subresources even if\n              the parent(base) resource's state is absent.\n            - Can be specified for each subresource.\n    do_wait_till_create:\n        type: bool\n        default: false\n        description:\n            - Can be used to wait for the realization of subresource before the\n              request to create the next resource is sent to the Manager.\n            - Can be specified for each subresource.\n    \"\"\"\n"
  },
  {
    "path": "plugins/module_utils/__init__.py",
    "content": ""
  },
  {
    "path": "plugins/module_utils/common_utils.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\nimport time\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import request\nfrom ansible.module_utils._text import to_native\nimport ipaddress\n\ndef check_if_valid_ip(address):\n    '''\n    params:\n    - ip_address: IP Address in string format\n    result:\n    checks if the IP address is valid or not.\n    '''\n    try:\n        ip = ipaddress.ip_address(address)\n        if isinstance(ip, ipaddress.IPv4Address):\n            ip_octets = address.split('.')\n            valid_ip_octets = [int(ip_octet) for ip_octet in ip_octets]\n            valid_ip_octets = [ip_octet for ip_octet in valid_ip_octets if ip_octet >= 0 and ip_octet<=255]\n            return len(ip_octets) == 4 and len(valid_ip_octets) == 4\n        elif isinstance(ip, ipaddress.IPv6Address):\n            return True\n    except ValueError:\n        return False\n\ndef traverse_and_retrieve_value(object , attribute_list):\n    '''\n    params:\n    - object: Object where value is to be searched from attribute list\n    - attribute_list: List to be used for searching attribute value\n    '''\n    if object is None:\n        return None\n    for attribute in attribute_list:\n        if object.__contains__(attribute):\n            object = object[attribute]\n        else:\n            raise Exception('AttributeError: Attribute value \\\"%s\\\" not found '\n                            'while traversing.' % attribute)\n    return object\n\ndef get_attribute_from_endpoint(module, manager_url, endpoint, mgr_username, \n                                mgr_password, validate_certs, attribute_name,\n                                fail_on_error=True):\n    '''\n    params:\n    - endpoint: API endpoint.\n    - attribute_name: Name of attribute whose value is required\n    result:\n    attribute value of the attribute name provided.\n    '''\n    try:\n        (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, \n                      validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n        if fail_on_error:\n            module.fail_json(msg='Error while retrieving'\n                             ' %s. Error [%s]' % (attribute_name, to_native(err)))\n        else:\n            return None\n    if resp.__contains__(attribute_name):\n        return resp[attribute_name]\n    return None\n\ndef get_id_from_display_name_results(module, manager_url, endpoint, mgr_username, \n                                     mgr_password, validate_certs, \n                                     search_attribute_list, return_attribute_list, \n                                     display_name, fail_module=True):\n    '''\n    params:\n    - endpoint: API endpoint.\n    - search_attribute_list: List of name attribute the depth to be searched in the result object\n    - return_attribute_list: List of name attribute the depth to be returned in the result object\n    - display_name: The name to be matched\n    - id_attribute: id_attribute whose value is to be returned\n    '''\n    try:\n        (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, \n                      validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n        module.fail_json(msg='Error while converting the passed name to'\n                             ' ID. Error [%s]' % to_native(err))\n    try:\n        for result in resp['results']:\n            if traverse_and_retrieve_value(result, search_attribute_list) == display_name:\n                return traverse_and_retrieve_value(result, return_attribute_list)\n    except Exception as err:\n        module.fail_json(msg='Error while getting id from display name. Error [%s]' % to_native(err))\n    if fail_module:\n        module.fail_json(msg='No id exist with display name %s' % display_name)\n    else:\n        return None\n\ndef wait_for_operation_to_execute(manager_url, endpoint, mgr_username, \n                                  mgr_password, validate_certs, attribute_list,\n                                  desired_attribute_values, undesired_attribute_values,\n                                  time_out=10800):\n    '''\n    params:\n    - endpoint: API endpoint.\n    - attribute_list: The attribute whose value should become the desired attribute value\n    - desired_attribute_value: The desired attribute value\n    \n    Function will wait till the attribute value derived from going deep to attribute list\n    becomes equal to desired_attribute_value.\n    '''\n    operation_time = 0\n    while True:\n        try:\n            (rc, resp) = request(manager_url + endpoint, headers=dict(Accept='application/json'),\n                                 url_username=mgr_username, url_password=mgr_password, \n                                 validate_certs=validate_certs, ignore_errors=True)\n        except Exception as err:\n            pass\n        try:\n            retrieved_value = traverse_and_retrieve_value(resp, attribute_list)\n            if retrieved_value in desired_attribute_values:\n                return None\n            if retrieved_value in undesired_attribute_values:\n                raise Exception(resp)\n        except Exception as err:\n            pass\n        time.sleep(10)\n        operation_time = operation_time + 10\n        if operation_time > time_out:\n            raise Exception('Operation timed out.')\n\ndef clean_and_get_params(args=None, extra_args_to_remove=[]):\n    '''\n    params:\n    - args: All the arguments to be removed\n    '''\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    args_to_remove.extend(extra_args_to_remove)\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_upgrade_orchestrator_node(module, mgr_hostname, mgr_username, mgr_password,\n                               headers, validate_certs):\n    '''\n    params:\n    - mgr_hostname: Any one of the manager node in manager cluster\n\n    Returns the upgrade orchestrator node  \n    '''\n    try:\n        (rc, resp) = request('https://%s/api/v1/node/services/install-upgrade' % mgr_hostname,\n               headers=headers, url_username=mgr_username, url_password=mgr_password, \n                             validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n        module.fail_json(changed=True, msg='Error getting ip address of the upgrade'\n                        ' orchestrator node. Error: {}'.format(err))\n    return resp['service_properties']['enabled_on'];\n"
  },
  {
    "path": "plugins/module_utils/nsxt_base_resource.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.policy_communicator import PolicyCommunicator\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.policy_communicator import DuplicateRequestError\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible.module_utils._text import to_native\n\nimport sys\nif sys.version_info[0] < 3:\n    raise Exception(\"Must be using Python 3\")\n\nfrom abc import ABC, abstractmethod\n\nimport time\nimport json\n\nimport inspect\n# Add all the base resources that can be configured in the\n# Policy API here. Required to infer base resource params.\nBASE_RESOURCES = {\"NSXTSegment\", \"NSXTTier0\", \"NSXTTier1\",\n                  \"NSXTSecurityPolicy\", \"NSXTPolicyGroup\",\n                  \"NSXTIpBlock\", \"NSXTIpPool\", \"NSXTBFDProfile\",\n                  \"NSXTGatewayPolicy\", \"NSXTL2BridgeEpProfile\"}\n\n\nclass NSXTBaseRealizableResource(ABC):\n\n    INCORRECT_ARGUMENT_NAME_VALUE = \"error_invalid_parameter\"\n\n    def realize(self, supports_check_mode=True,\n                successful_resource_exec_logs=[],\n                baseline_arg_names=[], resource_params=None):\n        # must call this method to realize the creation, update, or deletion of\n        # resource\n\n        self.resource_class = self.__class__\n\n        if not hasattr(self, \"_arg_spec\"):\n            # Base resource\n            self._make_ansible_arg_spec(\n                supports_check_mode=supports_check_mode)\n\n        if not hasattr(self, 'module'):\n            self.module = AnsibleModule(\n                argument_spec=self._arg_spec,\n                supports_check_mode=supports_check_mode)\n\n            self.set_baseline_args(baseline_arg_names)\n\n        # Infer manager credentials\n        mgr_hostname = self.module.params['hostname']\n        mgr_username = self.module.params['username']\n        mgr_password = self.module.params['password']\n        nsx_cert_path = self.module.params['nsx_cert_path']\n        nsx_key_path = self.module.params['nsx_key_path']\n\n        request_headers = self.module.params['request_headers']\n        ca_path = self.module.params['ca_path']\n        validate_certs = self.module.params['validate_certs']\n\n        # Each manager has an associated PolicyCommunicator\n        self.policy_communicator = PolicyCommunicator.get_instance(\n            mgr_hostname, mgr_username, mgr_password, nsx_cert_path,\n            nsx_key_path, request_headers, ca_path, validate_certs)\n\n        if resource_params is None:\n            resource_params = self.module.params\n\n        self.resource_params = resource_params\n\n        self._state = self.get_attribute('state', resource_params)\n        if not (hasattr(self, 'id') and self.id):\n            if self.get_resource_name() in BASE_RESOURCES:\n                self.id = self._get_id_using_attr_name(\n                    None, resource_params,\n                    self.get_resource_base_url(self.baseline_args),\n                    self.get_spec_identifier(),\n                    fail_if_not_found=False)\n            else:\n                self.id = self._get_id_using_attr_name(\n                    None, resource_params,\n                    self.get_resource_base_url(self._parent_info),\n                    self.get_spec_identifier(),\n                    fail_if_not_found=False)\n                if self.id is None:\n                    self.id = self.infer_resource_id(self._parent_info)\n                if self.id is None:\n                    self.module.fail_json(\n                        msg=\"Please specify either id or display_name for \"\n                            \"resource {}\".format(str(\n                                self.get_spec_identifier())))\n\n        # Extract the resource params from module\n        self.nsx_resource_params = self._extract_nsx_resource_params(\n            resource_params)\n\n        # parent_info is passed to subresources of a resource automatically\n        if not hasattr(self, \"_parent_info\"):\n            self._parent_info = {}\n        self.update_parent_info(self._parent_info)\n\n        try:\n            # get existing resource schema\n            _, self.existing_resource = self._send_request_to_API(\n                suffix=\"/\" + self.id, ignore_error=False,\n                accepted_error_codes=set([404]))\n            self.existing_resource_revision = self.existing_resource[\n                '_revision']\n            # As Policy API's PATCH requires all attributes to be filled,\n            # we fill the missing resource params (the params not specified)\n            # by user using the existing params\n            self._fill_missing_resource_params(\n                self.existing_resource, self.nsx_resource_params)\n        except Exception as err:\n            # the resource does not exist currently on the manager\n            self.existing_resource = None\n            self.existing_resource_revision = None\n        finally:\n            self._clean_none_resource_params(\n                self.existing_resource, self.nsx_resource_params)\n        self._achieve_state(resource_params, successful_resource_exec_logs)\n\n    @classmethod\n    def get_spec_identifier(cls):\n        # Can be overriden in the subclass to provide different\n        # unique_arg_identifier. It is used to infer which args belong to which\n        # subresource.\n        # By default, class name is used for subresources.\n        return cls.get_resource_name()\n\n    def get_state(self):\n        return self._state\n\n    def get_parent_info(self):\n        return self._parent_info\n\n    def infer_resource_id(self, parent_info):\n        # This is called when the user has not specified the ID or\n        # display_name of any child resource or its sub-resources\n        pass\n\n    @staticmethod\n    @abstractmethod\n    def get_resource_base_url(parent_info):\n        # Must be overridden by the subclass\n        raise NotImplementedError\n\n    @staticmethod\n    @abstractmethod\n    def get_resource_spec():\n        # Must be overridden by the subclass\n        raise NotImplementedError\n\n    @classmethod\n    def get_resource_name(cls):\n        return cls.__name__\n\n    def create_or_update_subresource_first(self):\n        # return True if subresource should be created/updated before parent\n        # resource\n        return self.resource_params.get(\n            \"create_or_update_subresource_first\", False)\n\n    def delete_subresource_first(self):\n        # return True if subresource should be deleted before parent resource\n        return self.resource_params.get(\"delete_subresource_first\", True)\n\n    def achieve_subresource_state_if_del_parent(self):\n        # return True if this resource is to be realized with its own specified\n        # state irrespective of the state of its parent resource.\n        return self.resource_params.get(\n            \"achieve_subresource_state_if_del_parent\", False)\n\n    def do_wait_till_create(self):\n        # By default, we do not wait for the parent resource to be created or\n        # updated before its subresource is to be realized.\n        return self.resource_params.get(\"do_wait_till_create\", False)\n\n    @staticmethod\n    def get_resource_update_priority():\n        # this priority can be used to create/delete subresources\n        # at the same level in a particular order.\n        # by default, it returns 1 so the resources are created/updated/\n        # deleted in a fixed but random order.\n        # should be overloaded in subclass to specify its priority.\n        # for creation or update, we iterate in descending order.\n        # for deletion, we iterate in ascending order.\n        return 1\n\n    def set_arg_spec(self, arg_spec):\n        self._arg_spec = arg_spec\n\n    def set_ansible_module(self, ansible_module):\n        self.module = ansible_module\n\n    def set_parent_info(self, parent_info):\n        self._parent_info = parent_info\n\n    def achieve_subresource_state(\n            self, resource_params, successful_resource_exec_logs):\n        \"\"\"\n            Achieve the state of each sub-resource.\n        \"\"\"\n        for sub_resource_class in self._get_sub_resources_class_of(\n                self.resource_class):\n            if sub_resource_class.allows_multiple_resource_spec():\n                children_resource_spec = (resource_params.get(\n                    sub_resource_class.get_spec_identifier()) or [])\n            else:\n                children_resource_spec = ([resource_params.get(\n                    sub_resource_class.get_spec_identifier())] or [])\n\n            # Update the parent pointer\n            my_parent = self._parent_info.get('_parent', '')\n            self._update_parent_info()\n\n            for resource_param_spec in children_resource_spec:\n                if resource_param_spec is not None:\n                    sub_resource = sub_resource_class()\n\n                    sub_resource.set_arg_spec(self._arg_spec)\n                    sub_resource.set_ansible_module(self.module)\n\n                    sub_resource.set_parent_info(self._parent_info)\n\n                    sub_resource.realize(\n                        successful_resource_exec_logs=(\n                            successful_resource_exec_logs),\n                        resource_params=resource_param_spec)\n\n            # Restore the parent pointer\n            self._parent_info['_parent'] = my_parent\n\n    def update_resource_params(self, nsx_resource_params):\n        # Can be used to updates the params of resource before making\n        # the API call.\n        # Should be overridden in the subclass if needed\n        pass\n\n    def check_for_update(self, existing_params, resource_params):\n        \"\"\"\n            resource_params: dict\n            existing_params: dict\n            Compares the existing_params with resource_params and returns\n            True if they are different. At a base level, it traverses the\n            params and matches one-to-one. If the value to be matched is a\n            - dict, it traverses that also.\n            - list, it merely compares the order.\n            Can be overriden in the subclass for specific custom checking.\n            Returns true if the params differ\n        \"\"\"\n        if not existing_params:\n            return False\n        for k, v in resource_params.items():\n            if k not in existing_params:\n                return True\n            elif type(v).__name__ == 'dict':\n                if self.check_for_update(existing_params[k], v):\n                    return True\n            elif v != existing_params[k]:\n                def compare_lists(list1, list2):\n                    # Returns True if list1 and list2 differ\n                    try:\n                        # If the lists can be converted into sets, do so and\n                        # compare lists as sets.\n                        set1 = set(list1)\n                        set2 = set(list2)\n                        return set1 != set2\n                    except Exception:\n                        return True\n                if type(v).__name__ == 'list':\n                    if compare_lists(v, existing_params[k]):\n                        return True\n                    continue\n                return True\n        return False\n\n    def update_parent_info(self, parent_info):\n        # Override this and fill in self._parent_info if that is to be passed\n        # to the sub-resource\n        # By default, parent's id is passed\n        parent_info[self.get_spec_identifier() + \"_id\"] = self.id\n\n    def get_attribute(self, attribute, resource_params):\n        \"\"\"\n            attribute: String\n            resource_params: Parameters of the resource\n        \"\"\"\n        if (attribute == \"state\" and\n                self.get_resource_name() not in BASE_RESOURCES):\n            # if parent has absent state, subresources should have absent\n            # state if . So, irrespective of what user specifies, if parent\n            # is to be deleted, the child resources will be deleted.\n            # override achieve_subresource_state_if_del_parent\n            # in resource class to change this behavior\n            if (self._parent_info[\"_parent\"].get_state() == \"absent\" and\n                    not self.achieve_subresource_state_if_del_parent()):\n                return \"absent\"\n        return resource_params.get(\n            attribute, self.INCORRECT_ARGUMENT_NAME_VALUE)\n\n    def set_baseline_args(self, baseline_arg_names):\n        # Can be overriden in subclass\n        self.baseline_args = {}\n        for baseline_arg_name in baseline_arg_names:\n            self.baseline_args[baseline_arg_name] = self.module.params[\n                baseline_arg_name]\n\n    def do_resource_params_have_attr_with_id_or_display_name(self, attr):\n        if (attr + \"_id\" in self.nsx_resource_params or\n                attr + \"_display_name\" in self.nsx_resource_params):\n            return True\n        return False\n\n    def get_id_using_attr_name_else_fail(self, attr_name, params,\n                                         resource_base_url, resource_type):\n        return self._get_id_using_attr_name(\n            attr_name, params, resource_base_url, resource_type,\n            fail_if_not_found=True)\n\n    def exit_with_failure(self, msg, **kwargs):\n        self.module.fail_json(msg=msg, **kwargs)\n\n    def skip_delete(self):\n        \"\"\"\n        Override in subclass if this resource is skipped to be deleted.\n        Note that the children of this resource will still be deleted unless\n        they override this method as well.\n        \"\"\"\n        return False\n\n    @classmethod\n    def is_required_in_spec(cls):\n        \"\"\"\n        Override in subclass if this resource is optional to be specified\n        in the ansible playbook.\n        \"\"\"\n        return False\n\n    @classmethod\n    def allows_multiple_resource_spec(cls):\n        \"\"\"\n        Override in the resource class definition with False if only one\n        resource can be associated with the parent. By default, we accept\n        multiple\n        \"\"\"\n        return True\n\n    def _get_id_using_attr_name(self, attr_name, params,\n                                resource_base_url, resource_type,\n                                fail_if_not_found=True):\n        # Pass attr_name '' or None to infer base resource's ID\n        id_identifier = 'id'\n        display_name_identifier = 'display_name'\n        if attr_name:\n            id_identifier = attr_name + \"_id\"\n            display_name_identifier = attr_name + \"_display_name\"\n        if id_identifier in params and params[id_identifier]:\n            return params.pop(id_identifier)\n        if (display_name_identifier in params and\n                params[display_name_identifier]):\n            resource_display_name = params.pop(display_name_identifier)\n            # Use display_name as ID if ID is not specified.\n            return (self.get_id_from_display_name(\n                resource_base_url, resource_display_name, resource_type,\n                not fail_if_not_found) or resource_display_name)\n        if fail_if_not_found:\n            # Incorrect usage of Ansible Module\n            self.module.fail_json(\n                msg=\"Please specify either {} id or display_name for the \"\n                    \"resource {}\".format(attr_name, str(resource_type)))\n\n    def get_id_from_display_name(self, resource_base_url,\n                                 resource_display_name,\n                                 resource_type, ignore_not_found_error=True):\n        try:\n            # Get the id from the Manager\n            (_, resp) = self._send_request_to_API(\n                resource_base_url=resource_base_url)\n            matched_resource = None\n            for resource in resp:\n                if (resource.__contains__('display_name') and\n                        resource['display_name'] == resource_display_name):\n                    if matched_resource is None:\n                        matched_resource = resource\n                    else:\n                        # Multiple resources with same display_name!\n                        # Ask the user to specify ID instead.\n                        self.module.fail_json(\n                            msg=\"Multiple {} found with display_name {}. \"\n                                \"Please specify the resource using id in \"\n                                \"the playbook.\".format(resource_type,\n                                                       resource_display_name))\n            if matched_resource is not None:\n                return matched_resource['id']\n            else:\n                if ignore_not_found_error:\n                    return None\n                else:\n                    # No resource found with this display_name\n                    self.module.fail_json(\n                        msg=\"No {} found with display_name {} for the \"\n                            \"specified configuration.\".format(\n                                resource_type, resource_display_name))\n        except Exception as e:\n            # Manager replied with invalid URL. It means that the resource\n            # does not exist on the Manager. So, return the display_name\n            return resource_display_name\n\n    def _update_parent_info(self):\n        # This update is always performed and should not be overriden by the\n        # subresource's class\n        self._parent_info[\"_parent\"] = self\n\n    def _make_ansible_arg_spec(self, supports_check_mode=True):\n        \"\"\"\n            We read the arg_spec of all the resources associated that\n            are associated with this resource and create one complete\n            arg_spec.\n        \"\"\"\n        if self.get_resource_name() in BASE_RESOURCES:\n            self._arg_spec = {}\n            # Update it with VMware arg spec\n            self._arg_spec.update(\n                PolicyCommunicator.get_vmware_argument_spec())\n\n            # ... then update it with top most resource spec ...\n            self._update_arg_spec_with_resource(\n                self.resource_class, self._arg_spec)\n            # Update with all sub-resources arg spec\n            for sub_resources_class in self._get_sub_resources_class_of(\n                    self.resource_class):\n                self._update_arg_spec_with_all_resources(\n                    sub_resources_class, self._arg_spec)\n\n    def _update_arg_spec_with_resource(self, resource_class, arg_spec):\n        # updates _arg_spec with resource_class's arg_spec\n        resource_arg_spec = self._get_base_arg_spec_of_resource()\n        resource_arg_spec.update(self._get_base_arg_spec_of_nsx_resource())\n        resource_arg_spec.update(resource_class.get_resource_spec())\n        if resource_class.__name__ not in BASE_RESOURCES:\n            arg_spec.update(\n                {\n                    resource_class.get_spec_identifier(): dict(\n                        options=resource_arg_spec,\n                        required=resource_class.is_required_in_spec(),\n                        type='dict',\n                    )\n                })\n            if resource_class.allows_multiple_resource_spec():\n                arg_spec[resource_class.get_spec_identifier()]['type'] = 'list'\n                arg_spec[resource_class.get_spec_identifier()]['elements'] = (\n                    'dict')\n        else:\n            arg_spec.update(resource_arg_spec)\n        return resource_arg_spec\n\n    def _update_arg_spec_with_all_resources(self, resource_class, arg_spec):\n        # updates _arg_spec with resource_class's arg_spec and all it's\n        # sub-resources\n        resource_arg_spec = self._update_arg_spec_with_resource(\n            resource_class, arg_spec)\n        # go to each child of resource_class and update it\n        for sub_resources_class in self._get_sub_resources_class_of(\n                resource_class):\n            self._update_arg_spec_with_all_resources(\n                sub_resources_class, resource_arg_spec)\n\n    def _get_base_arg_spec_of_nsx_resource(self):\n        resource_base_arg_spec = {}\n        resource_base_arg_spec.update(\n            # these are the base args for any NSXT Resource\n            display_name=dict(\n                required=False,\n                type='str'\n            ),\n            description=dict(\n                required=False,\n                type='str'\n            ),\n            tags=dict(\n                required=False,\n                type='list',\n                elements='dict',\n                options=dict(\n                    scope=dict(\n                        required=True,\n                        type='str'\n                    ),\n                    tag=dict(\n                        required=True,\n                        type='str'\n                    )\n                )\n            )\n        )\n        return resource_base_arg_spec\n\n    def _get_base_arg_spec_of_resource(self):\n        resource_base_arg_spec = {}\n        resource_base_arg_spec.update(\n            id=dict(\n                type='str'\n            ),\n            state=dict(\n                required=True,\n                type='str',\n                choices=['present', 'absent']\n            ),\n            create_or_update_subresource_first=dict(\n                default=False,\n                type='bool'\n            ),\n            delete_subresource_first=dict(\n                default=True,\n                type='bool'\n            ),\n            achieve_subresource_state_if_del_parent=dict(\n                default=False,\n                type='bool'\n            ),\n            do_wait_till_create=dict(\n                default=False,\n                type='bool'\n            )\n        )\n        return resource_base_arg_spec\n\n    def _extract_nsx_resource_params(self, resource_params):\n        # extract the params belonging to this resource only.\n        filtered_params = {}\n\n        def filter_with_spec(spec):\n            for key in spec.keys():\n                if (key in resource_params and\n                        resource_params[key] is not None):\n                    filtered_params[key] = resource_params[key]\n\n        filter_with_spec(self.get_resource_spec())\n        filter_with_spec(self._get_base_arg_spec_of_nsx_resource())\n        return filtered_params\n\n    def _achieve_present_state(self, successful_resource_exec_logs):\n        self.update_resource_params(self.nsx_resource_params)\n        is_resource_updated = self.check_for_update(\n            self.existing_resource, self.nsx_resource_params)\n        if not is_resource_updated:\n            # Either the resource does not exist or it exists but was not\n            # updated in the YAML.\n            if self.module.check_mode:\n                successful_resource_exec_logs.append({\n                    \"changed\": True,\n                    \"debug_out\": self.resource_params,\n                    \"id\": '12345',\n                    \"resource_type\": self.get_resource_name()\n                })\n                return\n            try:\n                if self.existing_resource:\n                    # Resource already exists\n                    successful_resource_exec_logs.append({\n                        \"changed\": False,\n                        \"id\": self.id,\n                        \"message\": \"%s with id %s already exists.\" %\n                        (self.get_resource_name(), self.id),\n                        \"resource_type\": self.get_resource_name()\n                    })\n                    return\n                # Create a new resource\n                _, resp = self._send_request_to_API(\n                    suffix=\"/\" + self.id, method='PATCH',\n                    data=self.nsx_resource_params)\n                if self.do_wait_till_create() and not self._wait_till_create():\n                    raise Exception\n\n                successful_resource_exec_logs.append({\n                    \"changed\": True,\n                    \"id\": self.id,\n                    \"body\": str(resp),\n                    \"message\": \"%s with id %s created.\" %\n                    (self.get_resource_name(), self.id),\n                    \"resource_type\": self.get_resource_name()\n                })\n            except Exception as err:\n                srel = successful_resource_exec_logs\n                self.module.fail_json(msg=\"Failed to add %s with id %s.\"\n                                          \"Request body [%s]. Error[%s].\"\n                                          % (self.get_resource_name(),\n                                             self.id, self.nsx_resource_params,\n                                             to_native(err)\n                                             ),\n                                      successfully_updated_resources=srel)\n        else:\n            # The resource exists and was updated in the YAML.\n            if self.module.check_mode:\n                successful_resource_exec_logs.append({\n                    \"changed\": True,\n                    \"debug_out\": self.resource_params,\n                    \"id\": self.id,\n                    \"resource_type\": self.get_resource_name()\n                })\n                return\n            self.nsx_resource_params['_revision'] = \\\n                self.existing_resource['_revision']\n            try:\n                _, patch_resp = self._send_request_to_API(\n                    suffix=\"/\"+self.id, method=\"PATCH\",\n                    data=self.nsx_resource_params)\n                # Get the resource again and compare version numbers\n                _, updated_resource_spec = self._send_request_to_API(\n                    suffix=\"/\"+self.id, method=\"GET\")\n                if updated_resource_spec[\n                        '_revision'] != self.existing_resource_revision:\n                    successful_resource_exec_logs.append({\n                        \"changed\": True,\n                        \"id\": self.id,\n                        \"body\": str(patch_resp),\n                        \"message\": \"%s with id %s updated.\" %\n                        (self.get_resource_name(), self.id),\n                        \"resource_type\": self.get_resource_name()\n                    })\n                else:\n                    successful_resource_exec_logs.append({\n                        \"changed\": False,\n                        \"id\": self.id,\n                        \"message\": \"%s with id %s already exists.\" %\n                        (self.get_resource_name(), self.id),\n                        \"resource_type\": self.get_resource_name()\n                    })\n            except Exception as err:\n                srel = successful_resource_exec_logs\n                self.module.fail_json(msg=\"Failed to update %s with id %s.\"\n                                          \"Request body [%s]. Error[%s].\" %\n                                          (self.get_resource_name(), self.id,\n                                           self.nsx_resource_params, to_native(\n                                               err)\n                                           ),\n                                      successfully_updated_resources=srel)\n\n    def _achieve_absent_state(self, successful_resource_exec_logs):\n        if self.skip_delete():\n            return\n\n        if self.existing_resource is None:\n            successful_resource_exec_logs.append({\n                \"changed\": False,\n                \"msg\": 'No %s exist with id %s' %\n                (self.get_resource_name(), self.id),\n                \"resource_type\": self.get_resource_name()\n            })\n            return\n        if self.module.check_mode:\n            successful_resource_exec_logs.append({\n                \"changed\": True,\n                \"debug_out\": self.resource_params,\n                \"id\": self.id,\n                \"resource_type\": self.get_resource_name()\n            })\n            return\n        try:\n            self._send_request_to_API(suffix=\"/\" + self.id, method='DELETE')\n            self._wait_till_delete()\n            successful_resource_exec_logs.append({\n                \"changed\": True,\n                \"id\": self.id,\n                \"message\": \"%s with id %s deleted.\" %\n                (self.get_resource_name(), self.id)\n            })\n        except Exception as err:\n            srel = successful_resource_exec_logs\n            self.module.fail_json(msg=\"Failed to delete %s with id %s. \"\n                                      \"Error[%s].\" % (self.get_resource_name(),\n                                                      self.id, to_native(err)),\n                                  successfully_updated_resources=srel)\n\n    def _send_request_to_API(self, suffix=\"\", ignore_error=False,\n                             method='GET', data=None,\n                             resource_base_url=None,\n                             accepted_error_codes=set()):\n        try:\n            if not resource_base_url:\n                if self.get_resource_name() not in BASE_RESOURCES:\n                    resource_base_url = (self.resource_class.\n                                         get_resource_base_url(\n                                             parent_info=self._parent_info))\n                else:\n                    resource_base_url = (self.resource_class.\n                                         get_resource_base_url(\n                                             baseline_args=self.baseline_args))\n            if not suffix:\n                rc, resp = self.policy_communicator.get_all_results(\n                    resource_base_url, ignore_errors=ignore_error)\n            else:\n                rc, resp = self.policy_communicator.request(\n                    resource_base_url + suffix,\n                    ignore_errors=ignore_error, method=method, data=data)\n            return rc, resp\n\n        except DuplicateRequestError:\n            self.module.fail_json(msg='Duplicate request')\n        except Exception as e:\n            if (e.args[0] not in accepted_error_codes and\n                    self.get_resource_name() in BASE_RESOURCES):\n                msg = ('Received {} from NSX Manager. Please try '\n                       'again. '.format(e.args[0]))\n                if len(e.args) == 2 and e.args[1] and (\n                        'error_message' in e.args[1]):\n                    msg += e.args[1]['error_message']\n                self.module.fail_json(msg=msg)\n            raise e\n\n    def get_all_resources_from_nsx(self):\n        rc, resp = self._send_request_to_API()\n        if rc != 200:\n            self.module.fail_json(\n                \"Invalid URL to retrieve all configured {} NSX \"\n                \"resources\".format(self.get_spec_identifier()))\n        return resp\n\n    def _achieve_state(self, resource_params,\n                       successful_resource_exec_logs=[]):\n        \"\"\"\n            Achieves `present` or `absent` state as specified in the YAML.\n        \"\"\"\n        if self.id == self.INCORRECT_ARGUMENT_NAME_VALUE:\n            # The resource was not specified in the YAML.\n            # So, no need to realize it.\n            return\n        if (self._state == \"present\" and\n                self.create_or_update_subresource_first()):\n            self.achieve_subresource_state(\n                resource_params, successful_resource_exec_logs)\n        if self._state == \"absent\" and self.delete_subresource_first():\n            self.achieve_subresource_state(\n                resource_params, successful_resource_exec_logs)\n\n        if self._state == 'present':\n            self._achieve_present_state(\n                successful_resource_exec_logs)\n        else:\n            self._achieve_absent_state(successful_resource_exec_logs)\n\n        if self._state == \"present\" and not (\n                self.create_or_update_subresource_first()):\n            self.achieve_subresource_state(\n                resource_params,\n                successful_resource_exec_logs=successful_resource_exec_logs)\n\n        if self._state == \"absent\" and not self.delete_subresource_first():\n            self.achieve_subresource_state(\n                resource_params, successful_resource_exec_logs)\n\n        if self.get_resource_name() in BASE_RESOURCES:\n            changed = False\n            for successful_resource_exec_log in successful_resource_exec_logs:\n                if successful_resource_exec_log[\"changed\"]:\n                    changed = True\n                    break\n            srel = successful_resource_exec_logs\n            self.module.exit_json(changed=changed,\n                                  successfully_updated_resources=srel)\n\n    def _get_sub_resources_class_of(self, resource_class):\n        subresources = []\n        for attr in resource_class.__dict__.values():\n            if (inspect.isclass(attr) and\n                    issubclass(attr, NSXTBaseRealizableResource)):\n                subresources.append(attr)\n        if hasattr(self, \"_state\") and self._state == \"present\":\n            subresources.sort(key=lambda subresource:\n                              subresource().get_resource_update_priority(),\n                              reverse=True)\n        else:\n            subresources.sort(key=lambda subresource:\n                              subresource().get_resource_update_priority(),\n                              reverse=False)\n        for subresource in subresources:\n            yield subresource\n\n    def _wait_till_delete(self):\n        \"\"\"\n            Periodically checks if the resource still exists on the API server\n            every 10 seconds. Returns after it has been deleted.\n        \"\"\"\n        while True:\n            try:\n                self._send_request_to_API(\n                    suffix=\"/\" + self.id, accepted_error_codes=set([404]))\n                time.sleep(10)\n            except DuplicateRequestError:\n                self.module.fail_json(msg='Duplicate request')\n            except Exception:\n                return\n\n    def _wait_till_create(self):\n        FAILED_STATES = [\"failed\"]\n        IN_PROGRESS_STATES = [\"pending\", \"in_progress\"]\n        SUCCESS_STATES = [\"partial_success\", \"success\"]\n        try:\n            count = 0\n            while True:\n                rc, resp = self._send_request_to_API(\n                    suffix=\"/\" + self.id, accepted_error_codes=set([404]))\n                if 'state' in resp:\n                    if any(resp['state'] in progress_status for progress_status\n                            in IN_PROGRESS_STATES):\n                        time.sleep(10)\n                        count = count + 1\n                        if count == 90:\n                            # Wait for max 15 minutes for host to realize\n                            return False\n                    elif any(resp['state'] in progress_status for\n                             progress_status in SUCCESS_STATES):\n                        return True\n                    else:\n                        # Failed State\n                        return False\n                else:\n                    if rc != 200:\n                        time.sleep(1)\n                        count = count + 1\n                        if count == 90:\n                            # Wait for max 15 minutes for host to realize\n                            return False\n                    else:\n                        return True\n        except Exception as err:\n            return False\n\n    def _fill_missing_resource_params(self, existing_params, resource_params):\n        \"\"\"\n            resource_params: dict\n            existing_params: dict\n            Fills resource_params with the key:value from existing_params if\n            missing in the former.\n        \"\"\"\n        if not existing_params:\n            return\n        for k, v in existing_params.items():\n            if k not in resource_params:\n                resource_params[k] = v\n            elif type(v).__name__ == 'dict':\n                self._fill_missing_resource_params(v, resource_params[k])\n\n    def _clean_none_resource_params(self, existing_params, resource_params):\n        keys_to_remove = []\n        for k, v in resource_params.items():\n            if v is None and (\n                    existing_params is None or k not in existing_params):\n                keys_to_remove.append(k)\n        for key in keys_to_remove:\n            resource_params.pop(key)\n        for k, v in resource_params.items():\n            if type(v).__name__ == 'dict':\n                self._clean_none_resource_params(existing_params, v)\n"
  },
  {
    "path": "plugins/module_utils/nsxt_resource_urls.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n# Hidden or not exposed URLS\n_SITE_URL = '/infra/sites'\n_DOMAIN_URL = '/infra/domains'\n_ENFORCEMENT_POINT_URL = _SITE_URL + '/{}/enforcement-points'\n\nIP_BLOCK_URL = '/infra/ip-blocks'\n\nIP_POOL_URL = '/infra/ip-pools'\nIP_ADDRESS_POOL_SUBNET_URL = IP_POOL_URL + '/{}/ip-subnets'\n\nPOLICY_GROUP_URL = _DOMAIN_URL + '/{}/groups'\n\nSECURITY_POLICY_URL = _DOMAIN_URL + '/{}/security-policies'\n\nSEGMENT_URL = '/infra/segments'\nSEGMENT_PORT_URL = SEGMENT_URL + '/{}/ports'\n\nTRANSPORT_ZONE_URL = _ENFORCEMENT_POINT_URL + '/{}/transport-zones'\n\nL2_BRIDGE_EP_PROFILE_URL = _ENFORCEMENT_POINT_URL + '/{}/edge-bridge-profiles'\n\nTIER_0_URL = '/infra/tier-0s'\nTIER_0_STATIC_ROUTE_URL = TIER_0_URL + '/{}/static-routes'\nTIER_0_LOCALE_SERVICE_URL = TIER_0_URL + '/{}/locale-services'\nTIER_0_LS_INTERFACE_URL = TIER_0_LOCALE_SERVICE_URL + '/{}/interfaces'\nTIER_0_BGP_NEIGHBOR_URL = TIER_0_LOCALE_SERVICE_URL + '/{}/bgp/neighbors'\nTIER_0_BFD_PEERS = TIER_0_STATIC_ROUTE_URL + '/bfd-peers'\n\nTIER_1_URL = '/infra/tier-1s'\nTIER_1_STATIC_ROUTE_URL = TIER_1_URL + '/{}/static-routes'\nTIER_1_LOCALE_SERVICE_URL = TIER_1_URL + '/{}/locale-services'\nTIER_1_LS_INTERFACE_URL = TIER_1_LOCALE_SERVICE_URL + '/{}/interfaces'\nTIER_1_BGP_NEIGHBOR_URL = TIER_1_LOCALE_SERVICE_URL + '/{}/bgp/neighbors'\n\nIPV6_DAD_PROFILE_URL = '/infra/ipv6-dad-profiles'\nIPV6_NDRA_PROFILE_URL = '/infra/ipv6-ndra-profiles'\n\nDHCP_RELAY_CONFIG_URL = '/infra/dhcp-relay-configs'\n\nEDGE_CLUSTER_URL = _ENFORCEMENT_POINT_URL + '/{}/edge-clusters'\nEDGE_NODE_URL = EDGE_CLUSTER_URL + '/{}/edge-nodes'\n\nVM_LIST_URL = '/virtual-machines'\nVM_UPDATE_URL = '/virtual-machines'\n\nBFD_PROFILE_URL = '/infra/bfd-profiles'\n\nGATEWAY_POLICY_URL = _DOMAIN_URL + '/{}/gateway-policies'\n"
  },
  {
    "path": "plugins/module_utils/policy_communicator.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\nimport json\nimport hashlib\n\nfrom ansible.module_utils.urls import open_url\nfrom ansible.module_utils.six.moves.urllib.error import HTTPError\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import get_certificate_file_path\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import is_json\n\nimport six.moves.urllib.parse as urlparse\n\n\nclass PolicyCommunicator:\n\n    __instances = dict()\n\n    @staticmethod\n    def check_for_authorization_header(request_headers):\n        if 'Authorization' in request_headers:\n            return True\n        return False\n\n    @staticmethod\n    def get_instance(mgr_hostname, mgr_username=None, mgr_password=None,\n                     nsx_cert_path=None, nsx_key_path=None, request_headers={},\n                     ca_path=None, validate_certs=True):\n        \"\"\"\n            Returns an instance of PolicyCommunicator associated with\n            (mgr_hostname, mgr_username, mgr_password) or\n            (mgr_hostname, nsx_cert_path, nsx_key_path)\n        \"\"\"\n        if mgr_username is not None:\n            if mgr_password is None:\n                raise InvalidInstanceRequest(\"mgr_password \")\n            key = tuple([mgr_hostname, mgr_username, mgr_password])\n        elif nsx_cert_path is not None:\n            if not nsx_cert_path.endswith('.p12') and nsx_key_path is None:\n                raise InvalidInstanceRequest(\"nsx_key_path\")\n            key = tuple([mgr_hostname, nsx_cert_path, nsx_key_path])\n        elif get_certificate_file_path('NSX_MANAGER_CERT_PATH') is not None:\n            nsx_cert_path = get_certificate_file_path('NSX_MANAGER_CERT_PATH')\n            key = tuple([mgr_hostname, nsx_cert_path])\n        elif PolicyCommunicator.check_for_authorization_header(\n                request_headers):\n            key = tuple([request_headers['Authorization']])\n        else:\n            raise InvalidInstanceRequest(\"(mgr_username, mgr_password) or\"\n                                         \"(nsx_cert_path, nsx_key_path), or \"\n                                         \"environment variable \"\n                                         \"'NSX_MANAGER_CERT_PATH'\")\n        if key not in PolicyCommunicator.__instances:\n            PolicyCommunicator(key, mgr_hostname, mgr_username, mgr_password,\n                               nsx_cert_path, nsx_key_path, request_headers,\n                               ca_path, validate_certs)\n        return PolicyCommunicator.__instances.get(key)\n\n    def __init__(self, key, mgr_hostname, mgr_username, mgr_password,\n                 nsx_cert_path, nsx_key_path, request_headers,\n                 ca_path, validate_certs):\n        if key in PolicyCommunicator.__instances:\n            raise Exception(\"The associated PolicyCommunicator is\"\n                            \" already present! Please use getInstance to\"\n                            \" retrieve it.\")\n        else:\n            self.use_basic_auth = False\n            if mgr_username is not None:\n                self.use_basic_auth = True\n            self.mgr_username = mgr_username\n            self.mgr_password = mgr_password\n            self.nsx_cert_path = nsx_cert_path\n            self.nsx_key_path = nsx_key_path\n\n            self.request_headers = request_headers or {}\n            self.request_headers.update({\n                'Accept': 'application/json',\n                'Content-Type': 'application/json'})\n\n            self.ca_path = ca_path\n            self.validate_certs = validate_certs\n\n            self.policy_url = 'https://{}/policy/api/v1'.format(mgr_hostname)\n            self.fabric_url = 'https://{}/api/v1/fabric'.format(mgr_hostname)\n            self.active_requests = set()\n\n            PolicyCommunicator.__instances[key] = self\n\n    @staticmethod\n    def get_vmware_argument_spec():\n        return dict(\n            hostname=dict(type='str', required=True),\n            username=dict(type='str', required=False),\n            password=dict(type='str', required=False, no_log=True),\n            port=dict(type='int', default=443),\n            validate_certs=dict(type='bool', required=False, default=True),\n            nsx_cert_path=dict(type='str', required=False),\n            nsx_key_path=dict(type='str', required=False),\n            request_headers=dict(type='dict'),\n            ca_path=dict(type='str')\n        )\n\n    def get_all_results(self, url, ignore_errors=False):\n        NULL_CURSOR_PREFIX = '0000'\n        rc, concatenate_response = self.request(\n            url, ignore_errors=ignore_errors)\n        if rc != 200:\n            return rc, None\n        cursor = concatenate_response.get('cursor', NULL_CURSOR_PREFIX)\n        op = '&' if urlparse.urlparse(url).query else '?'\n        url += op + 'cursor='\n        while cursor and not cursor.startswith(NULL_CURSOR_PREFIX):\n            rc, page = self.request(url + cursor, ignore_errors)\n            if rc != 200:\n                return rc, None\n            concatenate_response['results'].extend(page.get('results', []))\n            cursor = page.get('cursor', NULL_CURSOR_PREFIX)\n        return rc, concatenate_response['results']\n\n    def request(self, url, data=None, method='GET',\n                use_proxy=True, force=False, last_mod_time=None,\n                timeout=300, http_agent=None, ignore_errors=False, base_url='policy'):\n        if base_url == 'policy':\n            # prepend the policy url\n            # this is the default behavior if base_url is not specified\n            url = self.policy_url + url\n        elif base_url == 'fabric':\n            # prepend the fabric url\n            url = self.fabric_url + url\n        else:\n            raise Exception(\"invalid base_url specified in request call\")\n        # create a request ID associated with this request\n        request_id = self._get_request_id(url, data, method)\n        if self.register_request(request_id):\n            # new request\n            try:\n                # connect to the API server\n                if data is not None:\n                    data = json.dumps(data)\n                response = open_url(url=url, data=data,\n                                    headers=self.request_headers,\n                                    method=method,\n                                    use_proxy=use_proxy, force=force,\n                                    last_mod_time=last_mod_time,\n                                    timeout=timeout,\n                                    validate_certs=self.validate_certs,\n                                    url_username=self.mgr_username,\n                                    url_password=self.mgr_password,\n                                    http_agent=http_agent,\n                                    force_basic_auth=self.use_basic_auth,\n                                    client_cert=self.nsx_cert_path,\n                                    client_key=self.nsx_key_path,\n                                    ca_path=self.ca_path)\n            except HTTPError as err:\n                response = err\n            resp_code = response.getcode()\n            resp_raw_data = response.read().decode('utf-8')\n\n            # request completed by the server\n            self.active_requests.remove(request_id)\n\n            try:\n                resp_data = resp_raw_data\n                # infer the response\n                if resp_raw_data and is_json(resp_raw_data):\n                    resp_data = json.loads(resp_raw_data)\n            except Exception as e:\n                if not ignore_errors:\n                    raise Exception(resp_code, resp_raw_data)\n\n            # return the approprate response code and data\n            if resp_code >= 400 and not ignore_errors:\n                raise Exception(resp_code, resp_data)\n            if resp_data is not None and 'error_code' in resp_data:\n                raise Exception(resp_data['error_code'], resp_data)\n            else:\n                return resp_code, resp_data\n        else:\n            raise DuplicateRequestError\n\n    def _get_request_id(self, url, data=None, method='GET'):\n        \"\"\"\n            Creates a hash from url, data, and method that can be used\n            as a request ID.\n        \"\"\"\n        request = dict()\n        request[\"data\"] = data\n        request['request_url'] = url\n        request['request_method'] = method\n\n        return hashlib.sha256(\n            json.dumps(request, sort_keys=True).encode('utf-8')).hexdigest()\n\n    def register_request(self, request_id):\n        \"\"\"\n            This creates a hash from URL and data and stores it in a cache.\n            If a same hash is created, the request is identified as a duplicate\n            and it returns False. Otherwise, returns True.\n        \"\"\"\n        if request_id in self.active_requests:\n            return False\n        self.active_requests.add(request_id)\n        return True\n\n\nclass DuplicateRequestError(Exception):\n    pass\n\n\nclass InvalidInstanceRequest(Exception):\n\n    message = \"Invalid instance Request, missing {}\"\n\n    def __init__(self, missing_fields):\n        super(Exception, self).__init__(self.message.format(missing_fields))\n"
  },
  {
    "path": "plugins/module_utils/policy_resource_specs/__init__.py",
    "content": ""
  },
  {
    "path": "plugins/module_utils/policy_resource_specs/l2_bridge_ep_profile.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nSPEC = dict(\n    edge_nodes_info=dict(\n        required=True,\n        type='list',\n        elements='dict',\n        options=dict(\n            # Note that only default site_id and\n            # enforcementpoint_id are used\n            site_id=dict(\n                type='str',\n                default=\"default\"\n            ),\n            enforcementpoint_id=dict(\n                type='str',\n                default=\"default\"\n            ),\n            edge_cluster_id=dict(\n                type='str'\n            ),\n            edge_cluster_display_name=dict(\n                type='str'\n            ),\n            edge_node_id=dict(\n                type='str'\n            ),\n            edge_node_display_name=dict(\n                type='str'\n            )\n        )\n    ),\n    enforcementpoint_id=dict(\n        type='str',\n        default=\"default\"\n    ),\n    failover_mode=dict(\n        required=False,\n        default=\"PREEMPTIVE\",\n        choices=[\"PREEMPTIVE\", \"NON_PREEMPTIVE\"],\n        type='str'\n    ),\n    ha_mode=dict(\n        required=False,\n        type='str',\n        default=\"ACTIVE_STANDBY\",\n        choices=[\"ACTIVE_STANDBY\"]\n    ),\n    site_id=dict(\n        type='str',\n        default=\"default\"\n    ),\n)\n"
  },
  {
    "path": "plugins/module_utils/policy_resource_specs/security_policy.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nSPEC = dict(\n    category=dict(\n        required=False,\n        type='str'\n    ),\n    comments=dict(\n        required=False,\n        type='str'\n    ),\n    connectivity_strategy=dict(\n        required=False,\n        type='str',\n        choices=['WHITELIST', 'BLACKLIST', 'WHITELIST_ENABLE_LOGGING',\n                 'BLACKLIST_ENABLE_LOGGING', 'NONE']\n    ),\n    domain_id=dict(\n        required=False,\n        type='str',\n        default=\"default\"\n    ),\n    locked=dict(\n        required=False,\n        type='bool'\n    ),\n    scheduler_path=dict(\n        required=False,\n        type='str'\n    ),\n    scope=dict(\n        required=False,\n        type='list'\n    ),\n    sequence_number=dict(\n        required=False,\n        type='int'\n    ),\n    stateful=dict(\n        required=False,\n        type='bool'\n    ),\n    rules=dict(\n        required=False,\n        type='list',\n        elements='dict',\n        options=dict(\n            action=dict(\n                required=True,\n                type='str',\n                choices=[\"ALLOW\", \"DROP\", \"REJECT\"]\n            ),\n            description=dict(\n                required=False,\n                type='str'\n            ),\n            destination_groups=dict(\n                required=True,\n                type='list'\n            ),\n            destinations_excluded=dict(\n                required=False,\n                type='bool',\n                default=False\n            ),\n            direction=dict(\n                required=False,\n                default=\"IN_OUT\",\n                type='str',\n                choices=[\"IN_OUT\", \"IN\", \"OUT\"]\n            ),\n            disabled=dict(\n                required=False,\n                type='bool',\n                default=False\n            ),\n            display_name=dict(\n                type='str'\n            ),\n            id=dict(\n                type='str'\n            ),\n            ip_protocol=dict(\n                type='str',\n                choices=['IPV4', 'IPV6', 'IPV4_IPV6']\n            ),\n            logged=dict(\n                type='bool',\n                default=False\n            ),\n            notes=dict(\n                type='str'\n            ),\n            profiles=dict(\n                type='list',\n                elements='str'\n            ),\n            scope=dict(\n                type='list',\n                elements='str'\n            ),\n            sequence_number=dict(\n                required=False,\n                type='int'\n            ),\n            service_entries=dict(\n                type='list',\n                elements='dict'\n            ),\n            services=dict(\n                required=True,\n                type='list'\n            ),\n            source_groups=dict(\n                required=True,\n                type='list'\n            ),\n            sources_excluded=dict(\n                required=False,\n                type='bool',\n                default=False\n            ),\n            tag=dict(\n                type='str'\n            ),\n            tags=dict(\n                type='list',\n                elements='dict',\n                options=dict(\n                    scope=dict(\n                        type='str'\n                    ),\n                    tag=dict(\n                        type='str'\n                    )\n                )\n            ),\n        )\n    ),\n    tcp_strict=dict(\n        required=False,\n        type='bool'\n    )\n)\n"
  },
  {
    "path": "plugins/module_utils/upgrade_reverse_order.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\nimport time\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import get_upgrade_orchestrator_node\nfrom ansible.module_utils._text import to_native\n\n\nUPGRADE_API = '/upgrade/plan?action=upgrade'\nUPGRADE_STATUS_SUMMARY_API = '/upgrade/status-summary'\nMP_UPGRADE_DONE = False\n\ndef check_upgrade_status_at_start(module, manager_url, mgr_username, mgr_password, validate_certs):\n   global MP_UPGRADE_DONE\n\n   endpoint = \"/upgrade/upgrade-unit-groups?sync=true\"\n   call_get_sync(manager_url, endpoint, mgr_username, mgr_password, validate_certs)\n   \n   upgrade_status_summary = get_upgrade_status_summary(module, manager_url, mgr_username, mgr_password, validate_certs , False)\n\n   overall_upgrade_status = upgrade_status_summary['overall_upgrade_status']\n\n   if overall_upgrade_status == 'PAUSED' :\n      if upgrade_status_summary['component_status'][0]['status'] == 'SUCCESS':\n         MP_UPGRADE_DONE = True\n\n   return overall_upgrade_status\n\ndef get_upgrade_status_summary(module, manager_url, mgr_username, mgr_password, validate_certs , ignore_errors):\n  '''\n  Get the upgrade status summary\n  '''\n\n  try:\n        (rc, resp) = request(manager_url+ UPGRADE_STATUS_SUMMARY_API, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, \n                      validate_certs=validate_certs, ignore_errors=ignore_errors)\n  except Exception as err:\n          if ignore_errors:\n             return None\n          else:\n            module.fail_json(msg='Error while triggering api:'\n                            ' %s. Error [%s]' % (manager_url+ UPGRADE_STATUS_SUMMARY_API, to_native(err)))\n  return resp\n\ndef call_get_sync(managerUrl, endpoint, mgrUsername, mgrPassword, validateCerts):\n    request(managerUrl + endpoint, method='GET', url_username=mgrUsername, url_password=mgrPassword,\n            validate_certs=validateCerts, ignore_errors=True)\n\ndef check_component_upgrade_completion_status(module, manager_url, mgr_username, mgr_password, validate_certs):\n   global MP_UPGRADE_DONE\n   count_upgrade_status_api_no_resp = 0\n   component_upgrade_start_time = time.time()\n\n   while True:\n      upgrade_status_summary = get_upgrade_status_summary(module, manager_url, mgr_username, mgr_password, validate_certs , True)\n\n      if upgrade_status_summary == None:\n        count_upgrade_status_api_no_resp +=1\n\n      elif upgrade_status_summary.__contains__('overall_upgrade_status'):\n         overall_upgrade_status = upgrade_status_summary['overall_upgrade_status']\n\n         if overall_upgrade_status == 'SUCCESS':\n            module.exit_json(changed=True, message='System has been upgraded successfully!!!')\n            \n         elif overall_upgrade_status == 'PAUSED':\n            check_component_statuses(module , upgrade_status_summary['component_status'])\n            if not MP_UPGRADE_DONE:\n                MP_UPGRADE_DONE = True\n            return\n        \n      elapsed_time = time.time() - component_upgrade_start_time\n      if MP_UPGRADE_DONE and count_upgrade_status_api_no_resp >= 5:\n        module.fail_json(msg='Error while triggering api:'\n                    ' %s. API failed 5 times' %UPGRADE_STATUS_SUMMARY_API)\n      elif not MP_UPGRADE_DONE and elapsed_time > 3600 :\n         module.fail_json(msg='MP component upgrade took longer than 1hr, System upgrade failed')\n\n      time.sleep(30)\n       \n\ndef check_component_statuses(module, component_status_list):\n    for component_status in component_status_list:\n        if component_status['status'] == 'FAILED':\n            module.fail_json(msg='Failed to upgrade system as Component : %s'\n                        'has Status : %s ' %(component_status['component_type'], component_status['status']))\n      \n   \n\ndef execute_upgrade(module, manager_url, mgr_username, mgr_password, validate_certs):\n   global MP_UPGRADE_DONE\n   headers = dict(Accept=\"application/json\")\n   headers['Content-Type'] = 'application/json'\n\n   while True:\n      try:\n        (rc, resp) = request(manager_url+ UPGRADE_API,\n                        data='', headers=headers, method='POST', \n                        url_username=mgr_username, url_password=mgr_password, \n                        validate_certs=validate_certs, ignore_errors=False)\n      except Exception as err:\n        module.fail_json(msg=\"Failed while upgrading component\")\n\n      time.sleep(30)\n\n      check_component_upgrade_completion_status(module, manager_url, mgr_username, mgr_password, validate_certs)\n\n      \n\ndef trigger_upgrade_reverse_order(module, mgr_hostname, mgr_username, mgr_password, validate_certs):\n\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n\n    mgr_hostname = get_upgrade_orchestrator_node(module, mgr_hostname, mgr_username, \n                                            mgr_password, headers, validate_certs)\n    \n    manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n    upgrade_status = check_upgrade_status_at_start(module, manager_url, mgr_username,\n                                          mgr_password, validate_certs)\n\n    if upgrade_status == 'IN_PROGRESS' or upgrade_status == 'PAUSING':\n      module.fail_json(msg='Upgrade is in state: %s, can\\'t continue' % upgrade_status)\n\n    elif upgrade_status == 'SUCCESS':\n      module.exit_json(changed=False, message='Upgrade state is SUCCESS. No need to'\n                    ' continue.')\n      \n    elif upgrade_status == 'NOT_STARTED' or upgrade_status == 'PAUSED':\n      execute_upgrade(module, manager_url, mgr_username, mgr_password, validate_certs)"
  },
  {
    "path": "plugins/module_utils/vcenter_utils.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\nimport ssl\nimport requests\nimport atexit\n\ntry:\n    from pyvim import connect\nexcept:\n    from pyVim import connect\nfrom pyVmomi import vmodl\nfrom pyVmomi import vim\n\n\ndef establish_vcenter_connection(module, vCenter_host, username, password, ignore_ssl_verification):\n    \"\"\"\n    params:\n    - vCenter_host: vCenter host IP\n    - username: vCenter username\n    - password: vCenter password\n    result:\n    Retrieves vCenter information from service instance and returns as content object.\n    \"\"\"\n    if ignore_ssl_verification is False:\n        try:\n            sslContext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)\n            sslContext.verify_mode = ssl.CERT_NONE\n            service_instance = connect.SmartConnect(host=vCenter_host,\n                                                    user=username,\n                                                    pwd=password,\n                                                    port=443,\n                                                    sslContext=sslContext)\n            if not service_instance:\n                module.fail_json(msg=\"Could not connect to the specified vCenter \"\n                                     \"host using specified username and password\")\n\n            atexit.register(connect.Disconnect, service_instance)\n        except vmodl.MethodFault as error:\n            module.fail_json(msg=\"Caught vmodl fault while connecting to vCenter: \" + error.msg)\n    else:\n        try:\n            service_instance = connect.SmartConnect(host=vCenter_host,\n                                                    user=username,\n                                                    pwd=password,\n                                                    port=443)\n            if not service_instance:\n                module.fail_json(msg=\"Could not connect to the specified vCenter \"\n                                     \"host using specified username and password\")\n\n            atexit.register(connect.Disconnect, service_instance)\n        except (requests.ConnectionError, ssl.SSLError):\n            try:\n                sslContext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)\n                sslContext.verify_mode = ssl.CERT_NONE\n                service_instance = connect.SmartConnect(host=vCenter_host,\n                                                        user=username,\n                                                        pwd=password,\n                                                        port=443,\n                                                        sslContext=sslContext)\n                if not service_instance:\n                    module.fail_json(msg=\"Could not connect to the specified vCenter \"\n                                         \"host using specified username and password\")\n\n                atexit.register(connect.Disconnect, service_instance)\n            except vmodl.MethodFault as error:\n                module.fail_json(msg=\"Caught vmodl fault while connecting to vCenter: \" + error.msg)\n    return service_instance.RetrieveContent()\n\n\ndef get_resource_id_from_name(module, vCenter_host, username, password,\n                              resource_type, resource_name, ignore_ssl_verification):\n    \"\"\"\n    params:\n    - resource_type: Type of vCenter resource. Accepted values 'host', 'cluster', 'storage' and 'network'.\n    - resource_name: Name of the resource.\n    result:\n    - moref id of the resource name and type given.\n    \"\"\"\n    try:\n        content = establish_vcenter_connection(module, vCenter_host, username, password, ignore_ssl_verification)\n        if resource_type == 'host':\n            objview = content.viewManager.CreateContainerView(content.rootFolder,\n                                                              [vim.HostSystem], True)\n        elif resource_type == 'cluster':\n            objview = content.viewManager.CreateContainerView(content.rootFolder,\n                                                              [vim.ClusterComputeResource], True)\n        elif resource_type == 'storage':\n            objview = content.viewManager.CreateContainerView(content.rootFolder,\n                                                              [vim.Datastore], True)\n        elif resource_type == 'network':\n            objview = content.viewManager.CreateContainerView(content.rootFolder,\n                                                              [vim.Network], True)\n        else:\n            module.fail_json(msg='Resource type provided by user either doesn\\'t'\n                                 ' exist or is not supported')\n        all_resources = objview.view\n        objview.Destroy()\n        for resource in all_resources:\n            if resource.name == resource_name:\n                return resource._moId\n        module.fail_json(msg='%s doesnt exist in %s' % (resource_name,\n                                                        resource_type))\n    except vmodl.MethodFault as error:\n        print(\"Caught vmodl fault while fetching info from vCenter: \" + error.msg)\n        return -1\n\n\ndef get_data_network_id_from_name(module, vCenter_host, username, password,\n                                  data_network_name_list, ignore_ssl_verification):\n    \"\"\"\n    params:\n    - data_network_name_list: List of data network names\n    result:\n    list of data network ids.\n    \"\"\"\n    try:\n        content = establish_vcenter_connection(module, vCenter_host, username, password, ignore_ssl_verification)\n        objview = content.viewManager.CreateContainerView(content.rootFolder,\n                                                          [vim.Network], True)\n        all_networks = objview.view\n        objview.Destroy()\n        network_dict = {}\n        for network in all_networks:\n            network_dict[network.name] = network._moId\n        data_network_id_list = []\n        for data_network_name in data_network_name_list:\n            if data_network_name in network_dict:\n                data_network_id_list.append(str(network_dict[data_network_name]))\n            else:\n                module.fail_json(msg='data network %s doesnt exist in the available'\n                                     'list of networks' % data_network_name)\n        return data_network_id_list\n    except vmodl.MethodFault as error:\n        print(\"Caught vmodl fault while fetching info from vCenter: \" + error.msg)\n"
  },
  {
    "path": "plugins/module_utils/vmware_nsxt.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport json, os, re\nfrom ansible.module_utils.urls import open_url\nfrom ansible.module_utils.six.moves.urllib.error import HTTPError\nfrom ansible.module_utils._text import to_native\n\nimport six.moves.urllib.parse as urlparse\n\ndef vmware_argument_spec():\n    return dict(\n        hostname=dict(type='str', required=True),\n        username=dict(type='str', required=False),\n        password=dict(type='str', required=False, no_log=True),\n        port=dict(type='int', default=443),\n        validate_certs=dict(type='bool', required=False, default=True),\n    )\n\ndef request(url, data=None, headers=None, method='GET', use_proxy=True,\n            force=False, last_mod_time=None, timeout=300, validate_certs=True,\n            url_username=None, url_password=None, http_agent=None, force_basic_auth=True, ignore_errors=False):\n    '''\n    The main function which hits the request to the manager. Username and password are given the topmost priority.\n    In case username and password are not provided if the environment variable is set.\n    Authentication fails if the details are not correct.\n    '''\n    if url_username is None or url_password is None:\n        force_basic_auth = False\n        client_cert = get_certificate_file_path('NSX_MANAGER_CERT_PATH')\n        if client_cert is None:\n            raise Exception('It seems that either you have not passed your username password correctly or '\n                'your path for NSX_MANAGER_CERT_PATH is not set correctly.')\n    else:\n        client_cert = None\n\n    if method == 'GET':\n        return get_all_results(\n            url, data, headers, method, use_proxy, force, last_mod_time,\n            timeout, validate_certs, url_username, url_password, http_agent,\n            force_basic_auth, ignore_errors, client_cert)\n    return _request(\n        url, data, headers, method, use_proxy, force, last_mod_time, timeout,\n        validate_certs, url_username, url_password, http_agent,\n        force_basic_auth, ignore_errors, client_cert)\n\ndef get_all_results(\n        url, data, headers, method, use_proxy, force, last_mod_time, timeout,\n        validate_certs, url_username, url_password, http_agent,\n        force_basic_auth, ignore_errors, client_cert):\n    rc, resp = _request(\n        url, data, headers, method, use_proxy, force, last_mod_time, timeout,\n        validate_certs, url_username, url_password, http_agent,\n        force_basic_auth, ignore_errors, client_cert)\n    if rc != 200:\n        return rc, None\n    cursor = resp.get('cursor')\n    op = '&' if urlparse.urlparse(url).query else '?'\n    url += op + 'cursor='\n    NULL_CURSOR_PREFIX = '0000'\n    while cursor and not cursor.startswith(NULL_CURSOR_PREFIX):\n        rc, page = _request(\n            url + cursor, data, headers, method, use_proxy, force,\n            last_mod_time, timeout, validate_certs, url_username,\n            url_password, http_agent, force_basic_auth, ignore_errors,\n            client_cert)\n        if rc != 200:\n            return rc, None\n        resp['results'].extend(page.get('results', []))\n        cursor = page.get('cursor')\n    return rc, resp\n\ndef _request(url, data, headers, method, use_proxy,\n             force, last_mod_time, timeout, validate_certs,\n             url_username, url_password, http_agent, force_basic_auth,\n             ignore_errors, client_cert):\n    ca_path = get_certificate_file_path('NSX_MANAGER_CA_PATH')\n    resp_data = None\n    try:\n        r = open_url(\n            url=url, data=data, headers=headers, method=method,\n            use_proxy=use_proxy, force=force, last_mod_time=last_mod_time,\n            timeout=timeout, validate_certs=validate_certs,\n            url_username=url_username, url_password=url_password,\n            http_agent=http_agent, client_cert=client_cert,\n            force_basic_auth=force_basic_auth, ca_path=ca_path)\n    except HTTPError as err:\n        r = err\n\n    try:\n        raw_data = r.read().decode('utf-8')\n        if raw_data:\n            if is_json(raw_data):\n                resp_data = json.loads(raw_data)\n            else:\n                resp_data = raw_data\n    except Exception:\n        if not ignore_errors:\n            raise\n\n    resp_code = r.getcode()\n\n    if resp_code >= 400 and not ignore_errors:\n        raise Exception(resp_code, resp_data)\n    if not (resp_data is None) and resp_data.__contains__('error_code'):\n        raise Exception (resp_data['error_code'], resp_data)\n    return resp_code, resp_data\n\ndef get_certificate_string(crt_file):\n    '''\n    param: crt_file is the file containing the public key string\n    result: returns the public key(client certificate) string to be passed to the payload\n    how: String matching\n    '''\n    f = open(crt_file, 'r')\n    file_content = f.read()\n    file_content = file_content.split(\"\\n\")\n    certificate_string = \"\"\n    got_line_start = False\n    for string in file_content:\n        if string == \"-----BEGIN CERTIFICATE-----\":\n            got_line_start = True\n            certificate_string = certificate_string + string + \"\\n\"\n        elif string == \"-----END CERTIFICATE-----\":\n            certificate_string = certificate_string + \"\\n\" + string\n            break\n        elif got_line_start:\n            certificate_string = certificate_string + string\n        else:\n            pass\n    f.close()\n    return certificate_string\n\ndef get_private_key_string(p12_file):\n    '''\n    param: p12_file is the file containing the private key string\n    result: returns the private key string to be passed to the payload\n    how: String matching\n    '''\n    f = open(p12_file, 'r')\n    file_content = f.read()\n    file_content = file_content.split(\"\\n\")\n    certificate_string = \"\"\n    got_start_line = False\n    for string in file_content:\n        if re.match(\"-+BEGIN[ \\w]+PRIVATE[ ]+KEY-+\", string):\n            got_start_line = True\n            certificate_string = certificate_string + string + \"\\n\"\n        elif re.match(\"-+END[ \\w]+PRIVATE[ ]+KEY-+\", string):\n            certificate_string = certificate_string + \"\\n\" + string\n            break\n        elif got_start_line:\n            certificate_string = certificate_string + string\n        else:\n            pass\n    f.close()\n    return certificate_string\n\ndef get_certificate_file_path(environment_variable):\n    return os.getenv(environment_variable)\n\ndef get_vc_ip_from_display_name(module, manager_url, mgr_username, mgr_password,\n                                validate_certs, endpoint, display_name,\n                                exit_if_not_found=True):\n    '''\n    param:\n    display_name: Display name of the vC\n    result:\n    IP of the vC name provided\n    '''\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password,\n                      validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error occured while retrieving vCenter IP for %s. '\n                           'Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['server']\n    if exit_if_not_found:\n        module.fail_json(msg='vCenter with display name %s doesn\\'t exist.' % display_name)\n        return -1\n\ndef is_json(myjson):\n    '''\n    Param:\n    myjson: String to be checked\n    result:\n    Checks if the string is valid json or not.\n    '''\n    try:\n        json_object = json.loads(myjson)\n    except ValueError as e:\n        return False\n    return True\n\ndef version_tuple(v):\n    return tuple(map(int, (v.split(\".\"))))[:3] # Ignore build number\n\ndef get_nsx_version(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n        (rc, resp) = request(manager_url+ '/node/version', headers=dict(Accept='application/json'),\n                             url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n        module.fail_json(msg='Failed to retrieve NSX version. Error [%s]' % (to_native(err)))\n    return resp\n\ndef validate_nsx_mp_support(module, manager_url, mgr_username, mgr_password, validate_certs, err_msg=None):\n    version = get_nsx_version(module, manager_url, mgr_username, mgr_password, validate_certs)\n\n    # MP resources deprecated since v9.0.0\n    if version_tuple(version[\"product_version\"]) >= version_tuple(\"9.0.0\"):\n        if err_msg is None:\n            err_msg = 'NSX v9.0.0 and above do not support MP resources.'\n        module.fail_json(msg=err_msg)\n"
  },
  {
    "path": "plugins/modules/__init__.py",
    "content": ""
  },
  {
    "path": "plugins/modules/nsxt_certificates.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_certificates\nshort_description: 'Add a New Certificate'\ndescription: \"Adds a new private-public certificate or a chain of certificates (CAs) and, \n              optionally, a private key that can be applied to one of the user-facing \n              components (appliance management or edge). The certificate and the key \n              should be stored in PEM format. If no private key is provided, the \n              certificate is used as a client certificate in the trust store.\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    display_name:\n        description: 'Identifier to use when displaying entity in logs or GUI'\n        required: true\n        type: str\n    pem_encoded_file:\n        description: 'File containing pem encoded certificate data'\n        required: true\n        type: str\n    private_key_file:\n        description: 'File containing private key data'\n        required: false\n        type: str\n    passphrase:\n        description: 'Password for private key encryption'\n        required: false\n        type: str\n    description:\n        description: 'Description of this resource'\n        required: false\n        type: str\n    id:\n        description: 'Unique identifier of this resource'\n        required: false\n        type: str\n    key_algo:\n        description: 'Key algorithm contained in this certificate'\n        required: false\n        type: str\n    resource_type:\n        description: 'Must be set to the value TrustObjectData'\n        required: false\n        type: str\n    tags:\n        description: Opaque identifier meaninful to API user\n        required: false\n        type: Array of Tag\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n\n'''\n\nEXAMPLES = '''\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Add a new certificate\n      nsxt_certificates:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"Certificate_file\"\n        pem_encoded_file: \"/Path/to/crt/file\"\n        passphrase: \"paraphrase\"\n        state: \"present\"\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request, get_certificate_string, get_private_key_string\nfrom ansible.module_utils._text import to_native\n\ndef update_params_with_pem_encoding(certificate_params):\n    '''\n    params: Parameters passed to the certificate\n    result: Updated parameters. Files are replaced with the public and private strings. \n    '''\n    certificate_params['pem_encoded'] = get_certificate_string (certificate_params.pop('pem_encoded_file', None))\n    if certificate_params.get('private_key_file') is not None:\n        certificate_params['private_key'] = get_private_key_string (certificate_params.pop('private_key_file', None))\n    return certificate_params\n\ndef get_certificate_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_certificates(module, manager_url, mgr_username, mgr_password, validate_certs):\n  try:\n    (rc, resp) = request(manager_url+ '/trust-management/certificates', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing trust management certificates. Error [%s]' % (to_native(err)))\n  return resp\n\ndef get_certificate_with_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n  '''\n  result: returns the certificate object with the display name provided\n  '''\n  certificates = get_certificates(module, manager_url, mgr_username, mgr_password, validate_certs)\n  for certificate in certificates['results']:\n     if certificate.__contains__('display_name') and certificate['display_name'] == display_name:\n        return certificate\n  return None\n\ndef main():\n  argument_spec = dict()\n  argument_spec.update(hostname=dict(type='str', required=True),\n                       username=dict(type='str', required=True),\n                       password=dict(type='str', required=True, no_log=True),\n                       port=dict(type='int', default=443),\n                       validate_certs=dict(type='bool', requried=False, default=True),\n                       display_name=dict(required=True, type='str'),\n                       pem_encoded_file=dict(required=False, type='str', no_log=True), \n                       private_key_file=dict(required=False, type='str', no_log=True),\n                       passphrase=dict(required=False, type='str', no_log=True),\n                       description=dict(required=False, type='str'),\n                       id=dict(required=False, type='str'),\n                       key_algo=dict(required=False, type='str'),\n                       resource_type=dict(required=False, type='str'),\n                       tags=dict(required=False, type='list'),\n                    state=dict(required=True, choices=['present', 'absent']))\n  '''\n  Core function of the module reponsible for adding and deleting the certififcate.\n  '''\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  certificate_params = get_certificate_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  certificate_with_display_name = get_certificate_with_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n\n\n  if state == 'present':\n    # add the certificate\n    if certificate_with_display_name:\n      module.fail_json(msg=\"Certificate with display name \\'%s\\' already exists.\" % display_name)  \n    try:\n      certificate_params = update_params_with_pem_encoding(certificate_params)\n      headers = dict(Accept=\"application/json\")\n      headers['Content-Type'] = 'application/json'\n      request_data = json.dumps(certificate_params)\n      (rc, resp) = request(manager_url+ '/trust-management/certificates?action=import', data=request_data, headers=headers, method='POST',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg=\"Failed to add certificate.\\n Error: [%s].\\n Request_body[%s].\" % (to_native(err), request_data))\n\n    time.sleep(5)\n    module.exit_json(changed=True, result=resp, message=\"certificate created. Response: [%s]\" % str(resp))\n\n  elif state == 'absent': \n    #Delete the certificate   \n    if not certificate_with_display_name:\n      module.fail_json(msg=\"Certificate with display name \\'%s\\' doesn't exists.\" % display_name)\n    certificate_id = certificate_with_display_name['id']\n    try:\n       (rc, resp) = request(manager_url+ '/trust-management/certificates/' + certificate_id, method='DELETE',\n                            url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg=\"Failed to delete certificate with display name \\'%s\\'. Error[%s].\" % (display_name, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=certificate_id, message=\"Certificate with certificate id: %s deleted.\" % certificate_id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_certificates_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_certificates_facts\nshort_description: List all existing certificates\ndescription: Returns all certificate information viewable by the user, including each\n             certificate's UUID; resource_type (for example, certificate_self_signed,\n             certificate_ca, or certificate_signed); pem_encoded data; and history of the\n             certificate (who created or modified it and when). For additional\n             information, include the ?details=true modifier at the end of the request\n             URI.\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n\n'''\n\nEXAMPLES = '''\n- name: List all existing certificates\n  nsxt_certificates_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/trust-management/certificates', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing transport zone. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_cluster_profiles.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_cluster_profiles\nshort_description: 'Create a Cluster Profile'\ndescription: \"Create a cluster profile. The resource_type is required.\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    display_name:\n        description: 'Display name'\n        required: true\n        type: str\n    description:\n        description: Description of the resource\n        required: false\n        type: str\n    \n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n\n    \n'''\n\nEXAMPLES = '''\n  - name: Create Cluster Profiles\n    nsxt_cluster_profiles:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False `\n      resource_type: EdgeHighAvailabilityProfile\n      display_name: edge-cluster-profile-East\n      bfd_probe_interval: 1000\n      bfd_declare_dead_multiple: 3\n      bfd_allowed_hops: 1\n      state: present\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\n\ndef get_cluster_profiles_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_cluster_profiles(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/cluster-profiles', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing edge clusters. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['id']\n    module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef cmp_dict(dict1, dict2):\n    for k2, v2 in dict2.items():\n        found = False\n        if k2 not in dict1:\n            continue\n        if type(v2) != list and dict1[k2] != dict2[k2]:\n            return False\n        for obj2 in v2:\n            for obj1 in dict1[k2]:\n                if all(item in obj1.items() for item in obj2.items()):\n                           found = True\n        if not found:\n            return False\n    return True\n\ndef get_cluster_profiles_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    cluster_profiles = get_cluster_profiles(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for cluster_profile in cluster_profiles['results']:\n        if cluster_profile.__contains__('display_name') and cluster_profile['display_name'] == display_name:\n            return cluster_profile\n    return None\n\n# def ordered(obj):\n#     if isinstance(obj, dict):\n#         return sorted((k, ordered(v)) for k, v in obj.items())\n#     if isinstance(obj, list):\n#         return sorted(ordered(x) for x in obj)\n#     else:\n#         return obj\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, cluster_profiles_body):\n    existing_edge_cluster = get_cluster_profiles_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, cluster_profiles_body['display_name'])\n    if existing_edge_cluster is None:\n        return False\n    if existing_edge_cluster.__contains__('description') and not cluster_profiles_body.__contains__('description'):\n        return True\n    if not existing_edge_cluster.__contains__('description') and cluster_profiles_body.__contains__('description'):\n        return True\n    if existing_edge_cluster.__contains__('description') and cluster_profiles_body.__contains__('description') and \\\n        existing_edge_cluster['description'] != cluster_profiles_body['description']:\n        return True\n    if existing_edge_cluster.__contains__('bfd_allowed_hops') and not cluster_profiles_body.__contains__('bfd_allowed_hops'):\n        return True\n    if not existing_edge_cluster.__contains__('bfd_allowed_hops') and cluster_profiles_body.__contains__('bfd_allowed_hops'):\n        return True\n    if existing_edge_cluster.__contains__('bfd_allowed_hops') and cluster_profiles_body.__contains__('bfd_allowed_hops') and \\\n        existing_edge_cluster['bfd_allowed_hops'] != cluster_profiles_body['bfd_allowed_hops']:\n        return True\n    if existing_edge_cluster.__contains__('bfd_declare_dead_multiple') and not cluster_profiles_body.__contains__('bfd_declare_dead_multiple'):\n        return True\n    if not existing_edge_cluster.__contains__('bfd_declare_dead_multiple') and cluster_profiles_body.__contains__('bfd_declare_dead_multiple'):\n        return True\n    if existing_edge_cluster.__contains__('bfd_declare_dead_multiple') and cluster_profiles_body.__contains__('bfd_declare_dead_multiple') and \\\n        existing_edge_cluster['bfd_declare_dead_multiple'] != cluster_profiles_body['bfd_declare_dead_multiple']:\n        return True\n    if existing_edge_cluster.__contains__('standby_relocation_config') and not cluster_profiles_body.__contains__('standby_relocation_config'):\n        return True\n    if not existing_edge_cluster.__contains__('standby_relocation_config') and cluster_profiles_body.__contains__('standby_relocation_config'):\n        return True\n    if existing_edge_cluster.__contains__('standby_relocation_config') and cluster_profiles_body.__contains__('standby_relocation_config') and \\\n        not cmp_dict(existing_edge_cluster['standby_relocation_config'], cluster_profiles_body['standby_relocation_config']):\n        return True\n    return False\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, cluster_profile_params):\n    return cluster_profile_params\n\ndef get_profile_id_from_profile_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    cluster_profiles = get_cluster_profiles(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for cluster_profile in cluster_profiles['results']:\n        if cluster_profile.__contains__('display_name') and cluster_profile['display_name'] == display_name:\n            return cluster_profile['id']\n    module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef update_params_with_profile_id(module, manager_url, mgr_username, mgr_password, validate_certs, edge_cluster_params):\n    if edge_cluster_params.__contains__('cluster_profile_bindings'):\n        for cluster_profile in edge_cluster_params['cluster_profile_bindings']:\n            cluster_profile_name = cluster_profile.pop('profile_name', None)\n            cluster_profile['profile_id'] = get_profile_id_from_profile_name(module, manager_url, mgr_username, mgr_password, validate_certs, cluster_profile_name)\n    return edge_cluster_params\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                        description=dict(required=False, type='str'),\n                        resource_type=dict(required=True, type='str'),\n                        bfd_allowed_hops=dict(required=False, type='int'),\n                        bfd_declare_dead_multiple=dict(required=False, type='int'),\n                        bfd_probe_interval=dict(required=False, type='int'),\n                        standby_relocation_config=dict(required=False, type=dict,\n                        standby_relocation_threshold=dict(required=False, type='int')),\n                        tags=dict(required=False, type='list'),\n                        state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  cluster_profile_params = get_cluster_profiles_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  cluster_profiles_dict = get_cluster_profiles_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  cluster_profile_id, revision = None, None\n  if cluster_profiles_dict:\n    cluster_profile_id = cluster_profiles_dict['id']\n    revision = cluster_profiles_dict['_revision']\n\n  if state == 'present':\n    body = update_params_with_id(module, manager_url, mgr_username, mgr_password, validate_certs, cluster_profile_params)\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, body)\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n\n    if not updated:\n      # add the edge_cluster\n      request_data = json.dumps(body)\n      if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(request_data), id='12345')\n      try:\n          if cluster_profile_id:\n            module.exit_json(changed=False, id=cluster_profile_id, message=\"Cluster profile with display_name %s already exist.\"% module.params['display_name'])\n          (rc, resp) = request(manager_url+ '/cluster-profiles', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n                module.fail_json(msg=\"Failed to add cluster profile. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"Cluster profile with display name %s created.\" % module.params['display_name'])\n    else:\n      if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(edge_cluster_params)), id=cluster_profile_id)\n      body['_revision'] = revision # update current revision\n      request_data = json.dumps(body)\n      id = cluster_profile_id\n      try:\n          (rc, resp) = request(manager_url+ '/cluster-profiles/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update cluster profile with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"Cluster profile with id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the edge cluster\n    id = cluster_profile_id\n    if id is None:\n        module.exit_json(changed=False, msg='No cluster profile exist with display name %s' % display_name)\n\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(edge_cluster_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/cluster-profiles/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete cluster profile with id %s. Error[%s].\" % (id, to_native(err)))\n\n    module.exit_json(changed=True, id=id, message=\"Cluster profile with id %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_cluster_profiles_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_cluster_profiles_facts\nshort_description: List Cluster Profiles\ndescription: Returns paginated list of cluster profiles\n             Cluster profiles define policies for edge cluster and bridge cluster.\n\nversion_added: \"2.7\"\nauthor: Kommireddy Akhilesh\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: List Cluster Profiles\n  nsxt_cluster_profiles_facts:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/cluster-profiles', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing list of edge cluster. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_deploy_ova.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_deploy_ova\nshort_description: Deploys NSXT Manager\ndescription: Deploys NSXT Manager\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n    ovftool_path:\n        description: Path of ovf tool\n        type: 'str'\n    folder:\n        description:  vCenter folder\n        required: false\n        type: 'str'\n    datacenter:\n        description: Datacenter name\n        required: true \n        type: 'str'\n    datastore:\n        description: Data Store\n        required: true\n        type: 'str'\n    portgroup:\n        description: Port group\n        required: true\n        type: 'str'\n    portgroup_ext:\n        description: External Portgroup\n        type: 'str'\n    portgroup_transport:\n        description: Transport Port Group\n        type: 'str'\n    cluster:\n        description: vCenter Cluster\n        required: true\n        type: 'str'\n    vmname:\n        description: Name of VM\n        required: true\n        type: 'str'\n    hostname:\n        description: Name of host\n        required: true \n        type: 'str'\n    dns_server:\n        description: DNS server address\n        required: true\n        type: 'str'\n    ntp_server:\n        description: NTP Server Address\n        required: true\n        type: 'str'\n    dns_domain:\n        description: DNS Domain name\n        required: true\n        type: 'str'\n    gateway:\n        description: Gateway Address\n        required: true\n        type: 'str'\n    gateway6_0:\n        description: Gateway6 Address\n        required: false\n        type: 'str'\n    ip_address:\n        description: IP Address\n        required: true\n        type: 'str'\n    ip_address6_0:\n        description: IPv6 Address\n        required: false\n        type: 'str'\n    netmask:\n        description: Netmask\n        required: true\n        type: 'str'\n    netmask6_0:\n        description: Netmask6\n        required: true\n        type: 'str'\n    admin_password:\n        description: Admin Password\n        required: true\n        type: 'str'\n        no_log: true\n    cli_password:\n        description: CLI Password\n        required: true\n        type: 'str'\n        no_log: true\n    ssh_enabled:\n        description: If ssh is enabled\n        default: false\n    allow_ssh_root_login:\n        description: If SSH root login is allowed\n        default: false\n    deployment_size:\n        description: Size of the deployment\n        default: 'medium'\n        type: 'str'\n    path_to_ova:\n        description: Path to OVA file\n        required: true\n        type: 'str'\n    ova_file:\n        description: OVA File name\n        required: true\n        type: 'str'\n    disk_mode:\n        description: Disk mode to used. Thin or thick.\n        default: 'thin'\n    vcenter:\n        description: vCenter name\n        required: true\n        type: 'str'\n    vcenter_user:\n        description: vCenter username\n        required: true\n        type: 'str'\n    vcenter_passwd:\n        description: vCenter password\n        required: true\n        type: 'str'\n        no_log: true\n    extra_para:\n        description: Extra Parameters\n        required: false\n        type: 'str'\n    role:\n        description: Roles\n        required: true\n        type: 'str'\n    ip_protocol:\n        description: IP Protocol\n        required: false\n        type: 'str'\nrequirements:\n    - PyVmOmi - Python library for vCenter api.\n    - OVF Tools - Ovftool is used for ovf deployment.\n'''\n\nEXAMPLES = '''\n- name: Deploy NSX Manager OVA\n  deploy_ova:\n    ovftool_path: \"{{ ovfToolPath }}\"\n    datacenter: \"private_dc\"\n    datastore: \"data store\"\n    portgroup: \"VM Network\"\n    cluster: \"nsxt_cluster\"\n    vmname: \"nsxt-manager\"\n    hostname: \"nsxt-manager-10\"\n    dns_server: \"10.161.244.213\"\n    dns_domain: \"eng.vmware.com\"\n    ntp_server: \"123.108.200.124\"\n    gateway: \"10.112.203.253\"\n    gateway6_0: \"2620:124:6020:1045::253\"\n    ip_address: \"10.112.201.24\"\n    ip_address6_0: \"2620:124:6020:1045::1a\"\n    netmask: \"255.255.224.0\"\n    netmask6_0: \"64\"\n    admin_password: \"Admin!23Admin\"\n    cli_password: \"Admin!23Admin\"\n    path_to_ova: \"http://build-squid.eng.vmware.com/build/mts/release/bora-8411846/publish/nsx-unified-appliance/exports/ovf\"\n    ova_file: \"nsx-unified-appliance-2.2.0.0.0.8411854.ovf\"\n    vcenter: \"10.161.244.213\"\n    vcenter_user: \"administrator@vsphere.local\"\n    vcenter_passwd: \"Admin!23\"\n    deployment_size: \"small\"\n    role: \"nsx-manager nsx-controller\"\n    ip_protocol: IPv6\n\n'''\n\nRETURN = '''# '''\nimport requests\nimport ssl\n\nfrom pyVim.connect import SmartConnect\nfrom pyVmomi import vim, vmodl\n\n\ndef find_virtual_machine(content, searched_vm_name):\n    virtual_machines = get_all_objs(content, [vim.VirtualMachine])\n    for vm in virtual_machines:\n        if vm.name == searched_vm_name:\n            return vm\n    return None\n\n\ndef get_all_objs(content, vimtype):\n    obj = {}\n    container = content.viewManager.CreateContainerView(content.rootFolder, vimtype, True)\n    for managed_object_ref in container.view:\n        obj.update({managed_object_ref: managed_object_ref.name})\n    return obj\n\n\ndef connect_to_api(vchost, vc_user, vc_pwd):\n    try:\n        service_instance = SmartConnect(host=vchost, user=vc_user, pwd=vc_pwd)\n    except (requests.ConnectionError, ssl.SSLError):\n        try:\n            context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)\n            context.load_default_certs()\n            service_instance = SmartConnect(host=vchost, user=vc_user, pwd=vc_pwd, sslContext=context)\n        except Exception as e:\n            raise Exception(e)\n    return service_instance.RetrieveContent()\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=dict(\n            ovftool_path=dict(type='str'),\n            folder=dict(required=False, type='str'),\n            datacenter=dict(required=True, type='str'),\n            datastore=dict(required=True, type='str'),\n            portgroup=dict(required=True, type='str'),\n            portgroup_ext=dict(type='str'),\n            portgroup_transport=dict(type='str'),\n            cluster=dict(required=True, type='str'),\n            vmname=dict(required=True, type='str'),\n            hostname=dict(required=True, type='str'),\n            dns_server=dict(required=True, type='str'),\n            ntp_server=dict(required=True, type='str'),\n            dns_domain=dict(required=True, type='str'),\n            gateway=dict(required=True, type='str'),\n            gateway6_0=dict(type='str'),\n            ip_address=dict(required=True, type='str'),\n            ip_address6_0=dict(type='str'),\n            netmask=dict(required=True, type='str'),\n            netmask6_0=dict(type='str'),\n            admin_password=dict(required=True, type='str', no_log=True),\n            cli_password=dict(required=True, type='str', no_log=True),\n            ssh_enabled=dict(default=False),\n            allow_ssh_root_login=dict(default=False),\n            deployment_size=dict(default='medium', type='str'),\n            path_to_ova=dict(required=True, type='str'),\n            ova_file=dict(required=True, type='str'),\n            disk_mode=dict(default='thin'),\n            vcenter=dict(required=True, type='str'),\n            vcenter_user=dict(required=True, type='str'),\n            vcenter_passwd=dict(required=True, type='str', no_log=True),\n            extra_para=dict(type='str'),\n            role=dict(required=True, type='str'),\n            ip_protocol=dict(required=False, type='str')\n        ),\n        supports_check_mode=True,\n        required_together=[['gateway6_0', 'ip_address6_0', 'netmask6_0'], ['portgroup_ext', 'portgroup_transport']]\n    )\n\n    try:\n        content = connect_to_api(module.params['vcenter'], module.params['vcenter_user'],\n                                 module.params['vcenter_passwd'])\n    except vim.fault.InvalidLogin:\n        module.fail_json(msg='exception while connecting to vCenter, login failure, check username and password')\n    except requests.exceptions.ConnectionError:\n        module.fail_json(msg='exception while connecting to vCenter, check hostname, FQDN or IP')\n\n    nsx_manager_vm = find_virtual_machine(content, module.params['vmname'])\n\n    if nsx_manager_vm:\n        module.exit_json(changed=False, msg='A VM with the name {} was already present'.format(module.params['vmname']))\n\n    ovftool_exec = '{}/ovftool'.format(module.params['ovftool_path'])\n    ovf_command = [ovftool_exec]\n\n    ovf_base_options = ['--acceptAllEulas', '--skipManifestCheck', '--X:injectOvfEnv', '--powerOn', '--noSSLVerify',\n                        '--allowExtraConfig', '--diskMode={}'.format(module.params['disk_mode']),\n                        '--datastore={}'.format(module.params['datastore']),\n                        '--name={}'.format(module.params['vmname'])\n                        ]\n\n    if module.params['ip_protocol']:\n        ovf_base_options.extend(['--ipProtocol={}'.format(module.params['ip_protocol'])])\n\n    if module.params['portgroup_ext']:\n        ovf_base_options.extend(['--net:Network 0={}'.format(module.params['portgroup']),\n                                 '--net:Network 1={}'.format(module.params['portgroup_ext']),\n                                 '--net:Network 2={}'.format(module.params['portgroup_transport']),\n                                 '--net:Network 3={}'.format(module.params['portgroup'])])\n    else:\n        ovf_base_options.extend(['--network={}'.format(module.params['portgroup'])])\n    ovf_command.extend(ovf_base_options)\n\n    ovf_deployement_size = ['--deploymentOption={}'.format(module.params['deployment_size'])]\n    ovf_command.extend(ovf_deployement_size)\n\n    ovf_ext_prop = ['--prop:nsx_hostname={}'.format(module.params['hostname']),\n                    '--prop:nsx_dns1_0={}'.format(module.params['dns_server']),\n                    '--prop:nsx_domain_0={}'.format(module.params['dns_domain']),\n                    '--prop:nsx_ntp_0={}'.format(module.params['ntp_server']),\n                    '--prop:nsx_gateway_0={}'.format(module.params['gateway']),\n                    '--prop:nsx_ip_0={}'.format(module.params['ip_address']),\n                    '--prop:nsx_netmask_0={}'.format(module.params['netmask']),\n                    '--prop:nsx_passwd_0={}'.format(module.params['admin_password']),\n                    '--prop:nsx_cli_passwd_0={}'.format(module.params['cli_password']),\n                    '--prop:nsx_isSSHEnabled={}'.format(module.params['ssh_enabled']),\n                    '--prop:nsx_allowSSHRootLogin={}'.format(module.params['allow_ssh_root_login']),\n                    '--prop:nsx_role={}'.format(module.params['role'])]\n    ovf_command.extend(ovf_ext_prop)\n\n    if module.params['extra_para']:\n        ovf_command.extend(['--prop:extraPara={}'.format(module.params['extra_para'])])\n\n    if module.params['gateway6_0']:\n        ovf_command.extend(['--prop:nsx_gateway6_0={}'.format(module.params['gateway6_0'])])\n\n    if module.params['ip_address6_0']:\n        ovf_command.extend(['--prop:nsx_ip6_0={}'.format(module.params['ip_address6_0'])])\n\n    if module.params['netmask6_0']:\n        ovf_command.extend(['--prop:nsx_netmask6_0={}'.format(module.params['netmask6_0'])])\n\n    ova_file = '{}/{}'.format(module.params['path_to_ova'], module.params['ova_file'])\n    ovf_command.append(ova_file)\n\n    vi_string = 'vi://{}:{}@{}/'.format(module.params['vcenter_user'],\n                                        module.params['vcenter_passwd'], module.params['vcenter'])\n    if module.params.__contains__('folder') and module.params['folder']:\n        vi_string = vi_string + module.params['folder']\n\n    vi_string = vi_string + '/{}/host/{}/'.format(module.params['datacenter'], module.params['cluster'])\n\n    ovf_command.append(vi_string)\n\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=ovf_command)\n\n    ova_tool_result = module.run_command(ovf_command)\n\n    if ova_tool_result[0] != 0:\n        module.fail_json(msg='Failed to deploy OVA, error message from ovftool is: {}, the comand was {}'.format(ova_tool_result[1], ovf_command))\n\n    module.exit_json(changed=True, ova_tool_result=ova_tool_result)\n\nfrom ansible.module_utils.basic import *\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_edge_clusters.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_edge_clusters\nshort_description: 'Create Edge Cluster'\ndescription: \"Creates a new edge cluster.\n              It only supports homogeneous members.\n              The TransportNodes backed by EdgeNode are only allowed in cluster members.\n              DeploymentType (VIRTUAL_MACHINE|PHYSICAL_MACHINE) of these EdgeNodes is\n              recommended to be the same. EdgeCluster supports members of different\n              deployment types.\"\nversion_added: '2.7'\nauthor: 'Rahul Raghuvanshi'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    cluster_profile_bindings:\n        description: 'Edge cluster profile bindings'\n        required: false\n        type: 'array of ClusterProfileTypeIdEntry'\n    display_name:\n        description: 'Display name'\n        required: true\n        type: str\n    description:\n        description: Description of the resource\n        required: false\n        type: str\n    members:\n        description: \"EdgeCluster only supports homogeneous members.\n        These member should be backed by either EdgeNode or PublicCloudGatewayNode.\n        TransportNode type of these nodes should be the same.\n        DeploymentType (VIRTUAL_MACHINE|PHYSICAL_MACHINE) of these EdgeNodes is\n        recommended to be the same. EdgeCluster supports members of different\n        deployment types.\"\n        required: false\n        type: 'array of EdgeClusterMember'\n    allocation_rules:\n        description: Allocation rules for auto placement\n        required: false\n        type: list\n    enable_inter_site_forwarding:\n        description: Flag to enable inter site forwarding\n        required: false\n        type: bool\n    node_rtep_ips:\n        description: Remote tunnel endpoint ip address\n        required: false\n        type: list\n    member_node_type:\n        description: Node type of the cluster members\n        required: false\n        type: dict\n        EdgeDeploymentType:\n            description: Supported edge deployment type.\n            required: false\n            type: str\n    deployment_type:\n        description: Deplloyment type of the cluster members\n        required: false\n        type: dict\n        EdgeDeploymentType:\n            description: Supported edge deployment type.\n            required: false\n            type: str\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n\n    \n'''\n\nEXAMPLES = '''\n  - name: Create Edge Cluster\n    nsxt_edge_clusters:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      display_name: edge-cluster-1  `\n      cluster_profile_bindings:\n        - profile_name: \"nsx-edge-profile\"\n          resource_type: EdgeHighAvailabilityProfile\n      members:\n        - transport_node_name: \"TN_1\"\n      state: present\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\n\ndef get_edge_cluster_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_edge_clusters(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/edge-clusters', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing edge clusters. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['id']\n    module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef get_edge_clusters_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    edge_clusters = get_edge_clusters(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for edge_cluster in edge_clusters['results']:\n        if edge_cluster.__contains__('display_name') and edge_cluster['display_name'] == display_name:\n            return edge_cluster\n    return None\n\n# def ordered(obj):\n#     if isinstance(obj, dict):\n#         return sorted((k, ordered(v)) for k, v in obj.items())\n#     if isinstance(obj, list):\n#         return sorted(ordered(x) for x in obj)\n#     else:\n#         return obj\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, edge_cluster_with_id):\n    existing_edge_cluster = get_edge_clusters_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, edge_cluster_with_id['display_name'])\n    if existing_edge_cluster is None:\n        return False\n    if existing_edge_cluster.__contains__('description') and not edge_cluster_with_id.__contains__('description'):\n        return True\n    if not existing_edge_cluster.__contains__('description') and edge_cluster_with_id.__contains__('description'):\n        return True\n    if existing_edge_cluster.__contains__('description') and edge_cluster_with_id.__contains__('description') and \\\n        existing_edge_cluster['description'] != edge_cluster_with_id['description']:\n        return True\n    if existing_edge_cluster.__contains__('members') and not edge_cluster_with_id.__contains__('members'):\n        return True\n    if not existing_edge_cluster.__contains__('members') and edge_cluster_with_id.__contains__('members'):\n        return True\n    if existing_edge_cluster.__contains__('members') and edge_cluster_with_id.__contains__('members'):\n        if len(existing_edge_cluster['members']) != len(edge_cluster_with_id['members']):\n            return True\n        for count, member in enumerate(existing_edge_cluster['members']):\n            if member['transport_node_id'] != edge_cluster_with_id['members'][count]['transport_node_id']:\n                return True\n    return False\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, edge_cluster_params):\n    if edge_cluster_params.__contains__('members'):\n        for transport_node in edge_cluster_params['members']:\n            transport_node_name = transport_node.pop('transport_node_name', None)\n            transport_node['transport_node_id'] = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                                    \"/transport-nodes\", transport_node_name)\n    return edge_cluster_params\n\ndef get_cluster_profiles(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/cluster-profiles', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing edge clusters. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_profile_id_from_profile_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    cluster_profiles = get_cluster_profiles(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for cluster_profile in cluster_profiles['results']:\n        if cluster_profile.__contains__('display_name') and cluster_profile['display_name'] == display_name:\n            return cluster_profile['id']\n    module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef update_params_with_profile_id(module, manager_url, mgr_username, mgr_password, validate_certs, edge_cluster_params):\n    if edge_cluster_params.__contains__('cluster_profile_bindings'):\n        for cluster_profile in edge_cluster_params['cluster_profile_bindings']:\n            cluster_profile_name = cluster_profile.pop('profile_name', None)\n            cluster_profile['profile_id'] = get_profile_id_from_profile_name(module, manager_url, mgr_username, mgr_password, validate_certs, cluster_profile_name)\n    return edge_cluster_params\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                        description=dict(required=False, type='str'),\n                        cluster_profile_bindings=dict(required=False, type='list'),\n                        members=dict(required=False, type='list'), # tranpost_node_name\n                        allocation_rules=dict(required=False, type='list'),\n                        deployment_type=dict(required=False, type='dict',\n                        EdgeDeploymentType=dict(required=False, type='str')),\n                        enable_inter_site_forwarding=dict(required=False, type='bool'),\n                        member_node_type=dict(required=False, type='dict',\n                        EdgeClusterNodeType=dict(required=False, type='str')),\n                        node_rtep_ips=dict(required=False, type='str'),\n                        tags=dict(required=False, type='list'),\n                        state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  edge_cluster_params = get_edge_cluster_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  edge_cluster_dict = get_edge_clusters_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  edge_cluster_id, revision = None, None\n  if edge_cluster_dict:\n    edge_cluster_id = edge_cluster_dict['id']\n    revision = edge_cluster_dict['_revision']\n\n  if state == 'present':\n    body = update_params_with_id(module, manager_url, mgr_username, mgr_password, validate_certs, edge_cluster_params)\n    body = update_params_with_profile_id(module, manager_url, mgr_username, mgr_password, validate_certs, edge_cluster_params)\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, body)\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n\n    if not updated:\n      # add the edge_cluster\n      request_data = json.dumps(body)\n      if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(request_data), id='12345')\n      try:\n          if edge_cluster_id:\n            module.exit_json(changed=False, id=edge_cluster_id, message=\"Edge cluster with display_name %s already exist.\"% module.params['display_name'])\n          (rc, resp) = request(manager_url+ '/edge-clusters', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n                module.fail_json(msg=\"Failed to add edge cluster. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"edge cluster with display name %s created.\" % module.params['display_name'])\n    else:\n      if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(edge_cluster_params)), id=edge_cluster_id)\n      body['_revision'] = revision # update current revision\n      request_data = json.dumps(body)\n      id = edge_cluster_id\n      try:\n          (rc, resp) = request(manager_url+ '/edge-clusters/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update edge cluster with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"Edge cluster with edge cluster id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the edge cluster\n    id = edge_cluster_id\n    if id is None:\n        module.exit_json(changed=False, msg='No edge cluster exist with display name %s' % display_name)\n\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(edge_cluster_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/edge-clusters/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete edge cluster with id %s. Error[%s].\" % (id, to_native(err)))\n\n    module.exit_json(changed=True, id=id, message=\"edge cluster with edge cluster id %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_edge_clusters_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_edge_clusters_facts\nshort_description: List Edge Clusters\ndescription: Returns information about the configured edge clusters, which enable you to\n             group together transport nodes of the type EdgeNode and apply fabric\n             profiles to all members of the edge cluster. Each edge node can participate\n             in only one edge cluster.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: List Edge Clusters\n  nsxt_edge_clusters_facts:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/edge-clusters', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing list of edge cluster. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_fabric_compute_managers.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_fabric_compute_managers\nshort_description: 'Register compute manager with NSX'\ndescription: \"Registers compute manager with NSX. Inventory service will collect\n              data from the registered compute manager\"\nversion_added: '2.7'\nauthor: 'Rahul Raghuvanshi'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    credential:\n        asymmetric_credential:\n            description: 'Asymmetric login credential'\n            required: false\n            type: str\n        credential_key:\n            description: 'Credential key'\n            no_log: 'True'\n            required: false\n            type: str\n        credential_type:\n            description: 'Possible values are UsernamePasswordLoginCredential, VerifiableAsymmetricLoginCredential.'\n            required: true\n            type: str\n        credential_verifier:\n            description: 'Credential verifier'\n            required: false\n            type: str\n        description: 'Login credentials for the compute manager'\n        password:\n            description: \"Password for the user (optionally specified on PUT, unspecified on\n                          GET)\"\n            no_log: 'True'\n            required: false\n            type: str\n        required: false\n        thumbprint:\n            description: 'Hexadecimal SHA256 hash of the vIDM server''s X.509 certificate'\n            no_log: 'True'\n            required: false\n            type: str\n        type: dict\n        username:\n            description: 'Username value of the log'\n            required: false\n            type: str\n    display_name:\n        description: 'Display name'\n        required: true\n        type: str\n    origin_type:\n        description: 'Compute manager type like vCenter'\n        required: true\n        type: str\n    description:\n        description: 'Description of the resource'\n        required: false\n        type: str\n    server:\n        description: 'IP address or hostname of compute manager'\n        required: true\n        type: str\n    set_as_oidc_provider:\n        description: \"Specifies whether compute manager has been set as OIDC provider\n                        If the compute manager is VC and need to set set as OIDC provider for NSX then\n                        this flag should be set as true. This is specific to TKGS. NSX-T 3.0 only\"\n        required: false\n        type: bool\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n\n    \n'''\n\nEXAMPLES = '''\n- name: Register compute manager with NSX\n  nsxt_fabric_compute_managers:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    display_name: \"vCenter\"\n    server: \"10.161.244.213\"\n    description: \"Description of the resource\"\n    origin_type: vCenter\n    credential:\n      credential_type: \"UsernamePasswordLoginCredential\"\n      username: \"administrator@vsphere.local\"\n      password: \"Admin!23\"\n      thumbprint: \"36:43:34:D9:C2:06:27:4B:EE:C3:4A:AE:23:BF:76:A0:0C:4D:D6:8A:D3:16:55:97:62:07:C2:84:0C:D8:BA:66\"\n    state: present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\nimport ssl\nimport socket\nimport hashlib\n\ndef get_fabric_compute_manager_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_thumb(module):\n    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    sock.settimeout(10)\n    wrappedSocket = ssl.wrap_socket(sock)\n    try:\n      wrappedSocket.connect((module.params['server'], 443))\n    except:\n      module.fail_json(msg='Connection error while fatching thumbprint for server [%s].' % module.params['server'])\n    else:\n      der_cert_bin = wrappedSocket.getpeercert(True)\n      pem_cert = ssl.DER_cert_to_PEM_cert(wrappedSocket.getpeercert(True))\n      print(pem_cert)\n\n      #Thumbprint\n      thumb_sha256 = hashlib.sha256(der_cert_bin).hexdigest()\n      wrappedSocket.close()\n      # The API call expects the Thumbprint in Uppercase. While the API call is fixed,\n      # below is a quick fix\n      thumbprint = \"\"\n      thumbprint = ':'.join(a+b for a,b in zip(thumb_sha256[::2], thumb_sha256[1::2]))\n      return thumbprint.upper()\n\ndef get_fabric_compute_managers(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/fabric/compute-managers', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing fabric compute manager. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_compute_manager_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    compute_managers = get_fabric_compute_managers(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for compute_manager in compute_managers['results']:\n        if compute_manager.__contains__('display_name') and compute_manager['display_name'] == display_name:\n            return compute_manager\n    return None\n\ndef wait_till_create(id, module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      down_counter = 0\n      while True:\n          (rc, resp) = request(manager_url+ '/fabric/compute-managers/%s/status'% id, headers=dict(Accept='application/json'),\n                        url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n          if resp['registration_status'] == \"REGISTERING\" or resp['registration_status'] == \"UNREGISTERED\":\n              time.sleep(10)\n          elif resp['registration_status'] == \"REGISTERED\":\n            if resp[\"connection_status\"] == \"CONNECTING\":\n                time.sleep(10)\n            elif resp[\"connection_status\"] == \"DOWN\" and down_counter < 3:\n              time.sleep(10)\n              down_counter = down_counter + 1\n            elif resp[\"connection_status\"] == \"UP\":\n              time.sleep(5)\n              return\n            else:\n              module.fail_json(msg= 'Error connecting to compute manager. Connection status : %s'%(str(resp[\"connection_status\"])))\n          else:\n              module.fail_json(msg= 'Error in compute manager status: %s'%(str(resp['registration_status'])))\n    except Exception as err:\n      module.fail_json(msg='Error accessing compute manager status. Error [%s]' % (to_native(err)))\n\ndef wait_till_delete(id, module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      while True:\n          (rc, resp) = request(manager_url+ '/fabric/compute-managers/%s/status'% id, headers=dict(Accept='application/json'),\n                        url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n          time.sleep(10)\n    except Exception as err:\n      time.sleep(5)\n      return\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, compute_manager_with_ids):\n    existing_compute_manager = get_compute_manager_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, compute_manager_with_ids['display_name'])\n    if existing_compute_manager is None:\n        return False\n    if not existing_compute_manager.__contains__('description') and compute_manager_with_ids.__contains__('description'):\n        return True\n    if existing_compute_manager.__contains__('description') and compute_manager_with_ids.__contains__('description') and \\\n        existing_compute_manager['description'] != compute_manager_with_ids['description']:\n        return True\n    if existing_compute_manager['server'] != compute_manager_with_ids['server'] or \\\n        existing_compute_manager['credential']['thumbprint'] != compute_manager_with_ids['credential']['thumbprint'] or \\\n        existing_compute_manager['origin_type'] != compute_manager_with_ids['origin_type']:\n        return True\n    if existing_compute_manager.__contains__('set_as_oidc_provider') and compute_manager_with_ids.__contains__('set_as_oidc_provider') and \\\n        existing_compute_manager['set_as_oidc_provider'] != compute_manager_with_ids['set_as_oidc_provider']:\n        return True\n    return False\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                    credential=dict(required=False, type='dict', no_log=True,\n                    username=dict(required=False, type='str'),\n                    password=dict(required=False, type='str'),\n                    thumbprint=dict(required=False, type='str'),\n                    asymmetric_credential=dict(required=False, type='str'),\n                    credential_verifier=dict(required=False, type='str'),\n                    credential_key=dict(required=False, type='str', no_log=True),\n                    credential_type=dict(required=True, type='str')),\n                    origin_type=dict(required=True, type='str'),\n                    description=dict(required=False, type='str'),\n                    server=dict(required=True, type='str'),\n                    set_as_oidc_provider=dict(required=False, type='bool'),\n                    state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  fabric_compute_manager_params = get_fabric_compute_manager_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n  if not fabric_compute_manager_params['credential'].__contains__('thumbprint'):\n      fabric_compute_manager_params['credential']['thumbprint'] = get_thumb(module)\n\n  compute_manager_dict = get_compute_manager_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  compute_manager_id, revision = None, None\n  if compute_manager_dict:\n    compute_manager_id = compute_manager_dict['id']\n    revision = compute_manager_dict['_revision']\n\n  if state == 'present':\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, fabric_compute_manager_params)\n    if not updated:\n      # add the compute_manager\n      request_data = json.dumps(fabric_compute_manager_params)\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(request_data), id='12345')\n      try:\n          if compute_manager_id:\n              module.exit_json(changed=False, id=compute_manager_id, message=\"Compute manager with display_name %s already exist.\"% module.params['display_name'])\n          (rc, resp) = request(manager_url+ '/fabric/compute-managers', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n                module.fail_json(msg=\"Failed to add compute_manager. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      wait_till_create(resp['id'], module, manager_url, mgr_username, mgr_password, validate_certs)\n\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"fabric compute manager with ip %s created.\" % module.params['server'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(fabric_compute_manager_params)), id=compute_manager_id)\n      fabric_compute_manager_params['_revision'] = revision # update current revision\n      request_data = json.dumps(fabric_compute_manager_params)\n      id = compute_manager_id\n      try:\n          (rc, resp) = request(manager_url+ '/fabric/compute-managers/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update compute_manager with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"fabric compute manager with compute manager id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = compute_manager_id\n    if id is None:\n        module.exit_json(changed=False, msg='No compute manager exist with display_name %s' % display_name)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(fabric_compute_manager_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/fabric/compute-managers/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete fabric compute manager with id %s. Error[%s].\" % (id, to_native(err)))\n\n    wait_till_delete(id, module, manager_url, mgr_username, mgr_password, validate_certs)\n\n    module.exit_json(changed=True, id=id, message=\"fabric compute manager with compute manager id %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_fabric_compute_managers_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_fabric_compute_managers_facts\nshort_description: Return the List of Compute managers\ndescription: Returns information about all compute managers.\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: Lists all compute managers\n  nsxt_fabric_compute_managers_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils.urls import open_url, fetch_url\nfrom ansible.module_utils._text import to_native\nfrom ansible.module_utils.six.moves.urllib.error import HTTPError\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/fabric/compute-managers', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing fabric compute manager. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_global_manager_active.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2021 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_global_manager_active\nshort_description: 'Make the global manager as Active'\ndescription: \"Make the global manager as Active. This module has to be called using the details of global manager \n              which is to be made active\"\nversion_added: '3.2'\nauthor: 'Kaushik Lele'\noptions:\n    hostname:\n        description: 'Fully Qualified Domain Name of the Management Node which is to be made active'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    id:\n        description: 'Unique identifier of this global manager'\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: Make the global manager as Active\n  nsxt_global_manager_active:\n    fqdn: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    id: \"GM-1\"\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\nimport ssl\nimport socket\nimport hashlib\n\n\ndef get_global_managers(module, url, mgr_username, mgr_password, validate_certs):\n    try:\n        (rc, resp) = request(url, headers=dict(Accept='application/json'),\n                             url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                             ignore_errors=True)\n    except Exception as err:\n        module.fail_json(msg='Error accessing global manager. Error [%s]' % (to_native(err)))\n    return resp\n\n\ndef get_global_manager_from_id(module, url, mgr_username, mgr_password, validate_certs, id):\n    global_managers = get_global_managers(module, url, mgr_username, mgr_password, validate_certs)\n    for global_manager in global_managers['results']:\n        if global_manager.__contains__('id') and global_manager['id'] == id:\n            return global_manager\n    return None\n\n\ndef wait_till_switchover_complete(module, url, mgr_username, mgr_password, validate_certs):\n    try:\n        retry_count = 0\n        while True:\n            (rc, resp) = request(url, headers=dict(Accept='application/json'),\n                                 url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                                 ignore_errors=True)\n            if (resp['overall_status'] == \"ONGOING\" or resp['overall_status'] == \"NOT_STARTED\") and retry_count < 100:\n                time.sleep(10)\n            elif resp['overall_status'] == \"COMPLETE\":\n                return\n            else:\n                all_errors = ''\n                if resp['errors'] is not None:\n                    for e in resp['errors']:\n                        all_errors = all_errors + e\n                module.fail_json(msg='Switchover was not completed due to errors : %s' % all_errors)\n    except Exception as err:\n        module.fail_json(msg='Error checking switchover status. Error [%s]' % (to_native(err)))\n\n\ndef main():\n    argument_spec = vmware_argument_spec()\n    argument_spec.update(id=dict(required=True, type='str'))\n\n    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n    mgr_hostname = module.params['hostname']\n    mgr_username = module.params['username']\n    mgr_password = module.params['password']\n    validate_certs = module.params['validate_certs']\n    id = module.params['id']\n\n    manager_url = 'https://{}/global-manager/api/v1'.format(mgr_hostname)\n    global_manager_url = manager_url + '/global-infra/global-managers'\n    switchover_api_url = 'https://{}/api/v1/sites/switchover-status'.format(mgr_hostname)\n\n    existing_global_manager = get_global_manager_from_id(module, global_manager_url,\n                                                         mgr_username, mgr_password, validate_certs,\n                                                         id)\n    global_manager_id, revision = None, None\n\n    if existing_global_manager is None:\n        module.fail_json(msg=\"Global_manager with id [%s] not found.\" % id)\n\n    global_manager_id = existing_global_manager['id']\n    revision = existing_global_manager['_revision']\n    existing_global_manager[\"display_name\"]\n\n    if existing_global_manager[\"mode\"] == \"ACTIVE\":\n        module.exit_json(changed=False, id=global_manager_id,\n                         message=\"Global manager with id %s is already in ACTIVE mode.\" %\n                                 existing_global_manager[\"id\"])\n    else:\n        headers = dict(Accept=\"application/json\")\n        headers['Content-Type'] = 'application/json'\n\n        request_data_dict = existing_global_manager\n        request_data_dict[\"mode\"] = \"ACTIVE\"\n        request_data_dict.pop(\"connection_info\", None) \n        request_data = json.dumps(request_data_dict)\n\n        if module.check_mode:\n            module.exit_json(changed=True, debug_out=str(request_data), id=global_manager_id)\n\n        try:\n            (rc, resp) = request(global_manager_url + '/%s' % global_manager_id, data=request_data,\n                                 headers=headers, method='PUT',\n                                 url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                                 ignore_errors=True)\n        except Exception as err:\n            module.fail_json(msg=\"Failed to set global_manager as active. Request body [%s]. Error[%s].\" % (\n                request_data, to_native(err)))\n\n        wait_till_switchover_complete(module, switchover_api_url, mgr_username, mgr_password, validate_certs)\n\n        module.exit_json(changed=True, id=resp[\"id\"], body=str(resp),\n                         message=\"Global manager with id %s was made active.\" % module.params[\n                             'id'])\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_global_manager_enable_service.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2021 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_global_manager_enable_service\nshort_description: 'Enables global manager service first time after deployment and makes it active'\ndescription: \"Enables global manager service first time after deployment  and makes it active'\"\nversion_added: '3.2'\nauthor: 'Kaushik Lele'\noptions:\n    hostname:\n        description: 'Deployed NSX Global manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    display_name:\n        description: 'Identifier to use when displaying entity in logs or GUI. Defaults to ID if not set'\n        required: false\n        type: str\n    id:\n        description: 'Unique identifier of this global manager'\n        required: true\n        type: str        \n'''\n\nEXAMPLES = '''\n- name: Enables global manager service first time after deployment and makes it active\n  nsxt_global_manager_enable_service:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    display_name: \"GM First\"\n    id: \"GM-1\"\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\nimport ssl\nimport socket\nimport hashlib\n\n\ndef get_global_manager_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\n\ndef get_global_managers(module, url, mgr_username, mgr_password, validate_certs):\n    try:\n        (rc, resp) = request(url, headers=dict(Accept='application/json'),\n                             url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                             ignore_errors=True)\n    except Exception as err:\n        module.fail_json(msg='Error accessing global manager. Error [%s]' % (to_native(err)))\n    return resp\n\n\ndef get_global_manager_from_id(module, url, mgr_username, mgr_password, validate_certs, id):\n    global_managers = get_global_managers(module, url, mgr_username, mgr_password, validate_certs)\n    for global_manager in global_managers['results']:\n        if global_manager.__contains__('id') and global_manager['id'] == id:\n            return global_manager\n    return None\n\ndef main():\n    argument_spec = vmware_argument_spec()\n    argument_spec.update(username=dict(required=False, type='str'),\n                         password=dict(required=False, type='str'),\n                         hostname=dict(required=True, type='str'),\n                         display_name=dict(required=False, type='str'),\n                         id=dict(required=True, type='str'))\n\n    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n    global_manager_params = get_global_manager_params(module.params.copy())\n    mgr_hostname = module.params['hostname']\n    mgr_username = module.params['username']\n    mgr_password = module.params['password']\n    validate_certs = module.params['validate_certs']\n    id = module.params['id']\n    manager_url = 'https://{}/global-manager/api/v1'.format(mgr_hostname)\n    global_manager_api_url = manager_url + '/global-infra/global-managers'\n\n    existing_global_manager = get_global_manager_from_id(module, global_manager_api_url, mgr_username, mgr_password,\n                                                     validate_certs, id)\n    global_manager_id, revision = None, None\n\n    if existing_global_manager:\n        if existing_global_manager['mode'] == 'ACTIVE':\n            module.exit_json(changed=False, message=\"Global manager with id %s already exists in ACTIVE mode.\" % module.params['id'])\n        else:\n            module.fail_json(msg=\"Global manager with id %s as a standby mode. Use other module to make it active \" % module.params['id'])\n    else:\n        headers = dict(Accept=\"application/json\")\n        headers['Content-Type'] = 'application/json'\n\n        global_manager_params[\"mode\"] = \"ACTIVE\"\n        # add the global_manager\n        request_data = json.dumps(global_manager_params)\n\n        if module.check_mode:\n            module.exit_json(changed=True, debug_out=str(request_data), id=module.params['id'])\n\n        try:\n            (rc, resp) = request(global_manager_api_url + '/%s' % module.params['id'], data=request_data,\n                                     headers=headers, method='PATCH',\n                                     url_username=mgr_username, url_password=mgr_password,\n                                     validate_certs=validate_certs, ignore_errors=True)\n        except Exception as err:\n            module.fail_json(\n                    msg=\"Failed to activate global manager service. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n        module.exit_json(changed=True, id=module.params['id'], body=str(resp),\n                         message=\"Global manager with id %s is activated.\" % module.params['id'])\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_global_manager_registration.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2021 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_global_manager_registration\nshort_description: 'Register a standby global manager cluster'\ndescription: \"Register a standby global manager cluster\"\nversion_added: '3.2'\nauthor: 'Kaushik Lele'\noptions:\n    hostname:\n        description: 'Deployed NSX Global manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    connection_info:\n        description: 'Connection info (fqdn, password...)'\n        fqdn:\n            description: 'IP address or hostname of global manager(cluster)'\n            required: true\n            type: str\n        password:\n            description: \"Password for the user\"\n            no_log: 'True'\n            required: false\n            type: str\n        required: false\n        thumbprint:\n            description: 'Thumbprint of global manager in the form of a SHA-256 hash represented in lower case HEX'\n            no_log: 'True'\n            required: false\n            type: str\n        username:\n            description: 'Username to connect to global manager'\n            required: false\n            type: str\n    display_name:\n        description: 'Identifier to use when displaying entity in logs or GUI. Defaults to ID if not set'\n        required: false\n        type: str\n    description:\n        description: 'Description of this resource'\n        required: false\n        type: str\n    fail_if_rtt_exceeded:\n        description: 'Fail onboarding if maximum RTT exceeded.'\n        required: false\n        type: bool\n    id:\n        description: 'Unique identifier of this resource'\n        required: true\n        type: str\n    maximum_rtt:\n        description: \"Maximum acceptable packet round trip time (RTT). \n                If provided and fail_if_rtt_exceeded is true, onboarding of the site will\n                fail if measured RTT is greater than this value.\n                Minimum: 0\n                Maximum: 1000\n                Default: 250\"\n        required: false\n        type: int                           \n    mode:\n        choices:\n            - ACTIVE\n            - STANDBY\n        description: \"ACTIVE or STANDBY\"\n        required: true\n        type: str\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n\n    \n'''\n\nEXAMPLES = '''\n- name: Register a standby global manager cluster with exisitng global manager\n  nsxt_global_manager_registration:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    display_name: \"GM Second\"\n    id: \"GM-1\"\n    mode: \"STANDBY\"\n    connection_info:\n      fqdn: \"10.10.10.20\"\n      username: \"admin\"\n      password: \"Admin!23\"\n      thumbprint: \"1a4eeaef05ad711c84d688cfb72001d17a4965a963611d9af63fb86ff55276cf\"\n    state: present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\nimport ssl\nimport socket\nimport hashlib\n\n\ndef get_global_manager_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n\n    #   connection_info is an array\n    args[\"connection_info\"] = [args[\"connection_info\"]]\n    return args\n\n\ndef get_global_managers(module, url, mgr_username, mgr_password, validate_certs):\n    try:\n        (rc, resp) = request(url, headers=dict(Accept='application/json'),\n                             url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                             ignore_errors=True)\n    except Exception as err:\n        module.fail_json(msg='Error accessing global manager. Error [%s]' % (to_native(err)))\n    return resp\n\n\ndef get_global_manager_from_id(module, url, mgr_username, mgr_password, validate_certs, id):\n    global_managers = get_global_managers(module, url, mgr_username, mgr_password, validate_certs)\n    for global_manager in global_managers['results']:\n        if global_manager.__contains__('id') and global_manager['id'] == id:\n            return global_manager\n    return None\n\n\ndef check_for_update(module, url, mgr_username, mgr_password, validate_certs, global_manager_with_ids):\n    existing_global_manager = get_global_manager_from_id(module, url, mgr_username, mgr_password,\n                                                         validate_certs,\n                                                         global_manager_with_ids['id'])\n    if existing_global_manager is None:\n        return False\n\n    return True\n\n\ndef main():\n    argument_spec = vmware_argument_spec()\n    argument_spec.update(connection_info=dict(required=True, type='dict', no_log=True,\n                                              username=dict(required=False, type='str'),\n                                              password=dict(required=False, type='str'),\n                                              thumbprint=dict(required=False, type='str'),\n                                              fqdn=dict(required=True, type='str')),\n                         display_name=dict(required=False, type='str'),\n                         fail_if_rtt_exceeded=dict(required=False, type='str'),\n                         id=dict(required=True, type='str'),\n                         maximum_rtt=dict(required=False, type='int'),\n                         mode=dict(required=False, choices=['ACTIVE', 'STANDBY']),\n                         state=dict(required=True, choices=['present', 'absent']))\n\n    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n    global_manager_params = get_global_manager_params(module.params.copy())\n    state = module.params['state']\n    mgr_hostname = module.params['hostname']\n    mgr_username = module.params['username']\n    mgr_password = module.params['password']\n    validate_certs = module.params['validate_certs']\n    id = module.params['id']\n    manager_url = 'https://{}/global-manager/api/v1'.format(mgr_hostname)\n    global_manager_api_url = manager_url + '/global-infra/global-managers'\n\n    global_manager_dict = get_global_manager_from_id(module, global_manager_api_url, mgr_username, mgr_password,\n                                                     validate_certs, id)\n    global_manager_id, revision = None, None\n    if global_manager_dict:\n        global_manager_id = global_manager_dict['id']\n        revision = global_manager_dict['_revision']\n\n    if state == 'present':\n        headers = dict(Accept=\"application/json\")\n        headers['Content-Type'] = 'application/json'\n        updated = check_for_update(module, global_manager_api_url, mgr_username, mgr_password, validate_certs,\n                                   global_manager_params)\n        if not updated:\n            # add the global_manager\n            request_data = json.dumps(global_manager_params)\n            if module.check_mode:\n                module.exit_json(changed=True, debug_out=str(request_data), id='12345')\n            try:\n                if global_manager_id:\n                    module.exit_json(changed=False, id=global_manager_id,\n                                     message=\"Global manager with id %s already exist.\" % module.params['id'] )\n\n                (rc, resp) = request(global_manager_api_url + '/%s' % module.params['id'], data=request_data,\n                                     headers=headers, method='PUT',\n                                     url_username=mgr_username, url_password=mgr_password,\n                                     validate_certs=validate_certs, ignore_errors=True)\n            except Exception as err:\n                module.fail_json(\n                    msg=\"Failed to add global_manager. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n            module.exit_json(changed=True, id=resp[\"id\"], body=str(resp),\n                             message=\"Global manager with id %s is added.\" % module.params['id'])\n        else:\n            if module.check_mode:\n                module.exit_json(changed=True, debug_out=str(json.dumps(global_manager_params)), id=global_manager_id)\n            global_manager_params['_revision'] = revision  # update current revision\n            request_data = json.dumps(global_manager_params)\n            id = global_manager_id\n            try:\n                (rc, resp) = request(global_manager_api_url + '/%s' % id, data=request_data, headers=headers, method='PUT',\n                                     url_username=mgr_username, url_password=mgr_password,\n                                     validate_certs=validate_certs, ignore_errors=True)\n            except Exception as err:\n                module.fail_json(msg=\"Failed to update global manager with id %s. Request body [%s]. Error[%s].\" % (\n                id, request_data, to_native(err)))\n            module.exit_json(changed=True, id=resp[\"id\"], body=str(resp),\n                             message=\"Global manager with id %s updated.\" % id)\n\n    elif state == 'absent':\n        # delete the array\n        if global_manager_id is None:\n            module.exit_json(changed=False, msg='No global manager exists with id %s' % id)\n        if module.check_mode:\n            module.exit_json(changed=True, debug_out=str(json.dumps(global_manager_params)), id=id)\n        try:\n            (rc, resp) = request(global_manager_api_url + \"/%s\" % id, method='DELETE',\n                                 url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n        except Exception as err:\n            module.fail_json(msg=\"Failed to delete global manager with id %s. Error[%s].\" % (id, to_native(err)))\n\n        module.exit_json(changed=True, id=id, message=\"Global manager with id %s is deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_ip_blocks.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\nDOCUMENTATION = '''\n---\nmodule: nsxt_ip_blocks\nshort_description: 'Create a new IP address block.'\ndescription: \"Creates a new IPv4 address block using the specified cidr. cidr is a\n              required parameter. display_name & description are optional parameters\"\nversion_added: '2.7'\nauthor: 'Rahul Raghuvanshi'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    cidr:\n        description: \"Represents network address and the prefix length which will be                 associated\\nwith a layer-2 broadcast domain\"\n        required: true\n        type: str\n    display_name:\n        description: 'Display name'\n        required: true\n        type: str\n    description:\n        description: 'Description of the resource'\n        required: false\n        type: str\n    tags:\n        description: 'Opaque identifier meaningful to the API user'\n        required: false\n        type: list\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n    \n'''\n\nEXAMPLES = '''\n- name: Create a new IP address block\n  nsxt_ip_blocks:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    display_name: \"IPBlock-Tenant-1\"\n    description: \"IPBlock-Tenant-1 Description\"\n    cidr: \"192.168.0.0/16\"\n    state: present\n'''\n\nRETURN = '''# '''\n\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request, validate_nsx_mp_support\nfrom ansible.module_utils._text import to_native\n\ndef get_ip_block_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_ip_blocks(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/pools/ip-blocks', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing ip blocks. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_ip_block_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    ip_blocks = get_ip_blocks(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for ip_block in ip_blocks['results']:\n        if ip_block.__contains__('display_name') and ip_block['display_name'] == display_name:\n            return ip_block\n    return None\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, ip_block_params):\n    existing_ip_block = get_ip_block_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, ip_block_params['display_name'])\n    if existing_ip_block is None:\n        return False\n    if existing_ip_block['cidr'] != ip_block_params['cidr']:\n        return True\n    return False\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                        cidr=dict(required=True, type='str'),\n                        description=dict(required=False, type='str'),\n                        tags=dict(required=False, type='list'),\n                        state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  ip_block_params = get_ip_block_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  err_msg = 'NSX v9.0.0 and above do not support MP resources in nsxt_ip_blocks.py. Please use nsxt_policy_ip_block.py module.'\n  validate_nsx_mp_support(module, manager_url, mgr_username, mgr_password, validate_certs, err_msg)\n\n  block_dict = get_ip_block_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  block_id, revision = None, None\n  if block_dict:\n      block_id = block_dict['id']\n      revision = block_dict['_revision']\n\n  if state == 'present':\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, ip_block_params)\n\n    if not updated:\n      # add the block\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(ip_block_params)), id='12345')\n      request_data = json.dumps(ip_block_params)\n      try:\n          if block_id:\n              module.exit_json(changed=False, id=block_id, message=\"IP block with display_name %s already exist.\"% module.params['display_name'])\n          (rc, resp) = request(manager_url+ '/pools/ip-blocks', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to add ip block. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"IP block with display name %s created.\" % module.params['display_name'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(ip_block_params)), id=block_id)\n\n      ip_block_params['_revision'] = revision # update current revision\n      request_data = json.dumps(ip_block_params)\n      id = block_id\n      try:\n          (rc, resp) = request(manager_url+ '/pools/ip-blocks/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update ip block with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"ip block with block id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = block_id\n    if id is None:\n        module.exit_json(changed=False, msg='No ip block exist with display name %s' % display_name)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(ip_block_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/pools/ip-blocks/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete ip block with id %s. Error[%s].\" % (id, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=id, message=\"ip block with block id %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_ip_blocks_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils.urls import open_url, fetch_url\nfrom ansible.module_utils._text import to_native\nfrom ansible.module_utils.six.moves.urllib.error import HTTPError\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_ip_blocks_facts\nshort_description: Returns list of configured IP address blocks.\ndescription: Returns information about configured IP address blocks. Information includes\n             the id, display name, description & CIDR of IP address blocks\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: Lists all configured IP address blocks\n  nsxt_ip_block_facts:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n'''\n\nRETURN = '''# '''\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  #raise ValueError(argument_spec)\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  #raise ValueError(argument_spec)\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/pools/ip-blocks', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing list of ip blocks. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_ip_pools.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\nDOCUMENTATION = '''\n---\nmodule: nsxt_ip_pools\nshort_description: 'Create an IP Pool'\ndescription: \"Creates a new IPv4 or IPv6 address pool. Required parameters are\n              allocation_ranges and cidr. Optional parameters are display_name,\n              description, dns_nameservers, dns_suffix, and gateway_ip.\"\nversion_added: '2.7'\nauthor: 'Rahul Raghuvanshi'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    display_name:\n        description: 'Display name'\n        required: true\n        type: str\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n    subnets:\n        description: \"Subnets can be IPv4 or IPv6 and they should not overlap. The maximum\n                      number will not exceed 5 subnets.\"\n        required: false\n        type: 'array of IpPoolSubnet'\n    tags:\n        description: 'Opaque identifiers meaningful to the API user'\n        required: false\n        type: str\n    description:\n        description: 'description of the resource'\n        required: false\n        type: str\n    ip_release_delay:\n        description: 'IP address release delay'\n        required: false\n        type: int\n\n    \n'''\n\nEXAMPLES = '''\n- name: Create ip pool\n  nsxt_ip_pools:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    display_name: IPPool-IPV4-1\n    subnets:\n    - allocation_ranges:\n      - start: \"10.112.201.28\"\n        end: \"10.112.201.29\"\n      cidr: \"10.112.201.0/24\"\n    state: \"present\"\n'''\n\nRETURN = '''# '''\n\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request, validate_nsx_mp_support\nfrom ansible.module_utils._text import to_native\n\ndef get_ip_pool_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_ip_pools(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/pools/ip-pools', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing ip pools. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_ip_pool_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    ip_pools = get_ip_pools(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for ip_pool in ip_pools['results']:\n        if ip_pool.__contains__('display_name') and ip_pool['display_name'] == display_name:\n            return ip_pool\n    return None\n\n# def ordered(obj):\n#     if isinstance(obj, dict):\n#         return sorted((k, ordered(v)) for k, v in obj.items())\n#     if isinstance(obj, list):\n#         return sorted(ordered(x) for x in obj)\n#     else:\n#         return obj\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, ip_pool_params):\n    existing_ip_pool = get_ip_pool_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, ip_pool_params['display_name'])\n    if existing_ip_pool is None:\n        return False\n    if  existing_ip_pool.__contains__('subnets') and ip_pool_params.__contains__('subnets') and existing_ip_pool['subnets'] != ip_pool_params['subnets']:\n        return True\n    return False\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                        subnets=dict(required=False, type='list'),\n                        tags=dict(required=False, type='list'),\n                        description=dict(required=False, type='str'),\n                        ip_release_delay=dict(required=False, type='int'),\n                        state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  ip_pool_params = get_ip_pool_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  err_msg = 'NSX v9.0.0 and above do not support MP resources in nsxt_ip_pools.py. Please use nsxt_policy_ip_pool.py module.'\n  validate_nsx_mp_support(module, manager_url, mgr_username, mgr_password, validate_certs, err_msg)\n\n  pool_dict = get_ip_pool_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  pool_id, revision = None, None\n  if pool_dict:\n    pool_id = pool_dict['id']\n    revision = pool_dict['_revision']\n\n  if state == 'present':\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, ip_pool_params)\n\n    if not updated:\n      # add the pool\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(ip_pool_params)), id='12345')\n      request_data = json.dumps(ip_pool_params)\n      try:\n          if pool_id:\n              module.exit_json(changed=False, id=pool_id, message=\"IP pool with display_name %s already exist.\"% module.params['display_name'])\n          (rc, resp) = request(manager_url+ '/pools/ip-pools', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to add ip pool. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"IP pool with display name %s created.\" % module.params['display_name'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(ip_pool_params)), id=pool_id)\n      ip_pool_params['_revision']=revision # update current revision\n      request_data = json.dumps(ip_pool_params)\n      id = pool_id\n      try:\n          (rc, resp) = request(manager_url+ '/pools/ip-pools/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update ip pool with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"ip pool with pool id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = pool_id\n    if id is None:\n        module.exit_json(changed=False, msg='No ip pool exist with display name %s' % display_name)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(ip_pool_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/pools/ip-pools/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete ip pool with id %s. Error[%s].\" % (id, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=id, message=\"ip pool with pool id %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_ip_pools_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_ip_pools_facts\nshort_description: List IP Pools\ndescription: Returns information about the configured IP address pools. Information\n             includes the display name and description of the pool and the details of\n             each of the subnets in the pool, including the DNS servers, allocation\n             ranges, gateway, and CIDR subnet address.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: List IP Pools\n  nsxt_ip_pools_facts:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils.urls import open_url, fetch_url\nfrom ansible.module_utils._text import to_native\nfrom ansible.module_utils.six.moves.urllib.error import HTTPError\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/pools/ip-pools', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing list of ip pools. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_licenses.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_licenses\nshort_description: 'Add a new license key'\ndescription: \"This will add a license key to the system.\n              The API supports adding only one license key for each license edition\n              type - Standard, Advanced or Enterprise. If a new license key is tried\n              to add for an edition for which the license key already exists,\n              then this API will return an error.\"\nversion_added: '2.7'\nauthor: 'Rahul Raghuvanshi'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    license_key:\n        description: 'license key'\n        no_log: 'True'\n        required: true\n        type: str\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true   \n'''\n\nEXAMPLES = '''\n- name: Add license\n  nsxt_licenses:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      license_key: \"11111-22222-33333-44444-55555\"\n      state: present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef get_license_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef check_license_exist(module, manager_url, mgr_username, mgr_password, validate_certs):\n    id = module.params['license_key']\n    try:\n      (rc, resp) = request(manager_url+ '/licenses/%s' % id, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      return False\n    return True\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(license_key=dict(required=True, type='str', no_log=True),\n                    state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  license_params = get_license_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n  request_data = json.dumps(license_params)\n\n  if state == 'present':\n    # add the license\n    if check_license_exist(module, manager_url, mgr_username, mgr_password, validate_certs):\n        module.exit_json(changed=False, message=\"license with license key %s already exist.\"% module.params['license_key'])\n    if module.check_mode:\n       module.exit_json(changed=True, debug_out=str(request_data), id=module.params['license_key'])\n    try:\n        (rc, resp) = request(manager_url+ '/licenses', data=request_data, headers=headers, method='POST',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to add license. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, result=resp, message=\"license with license key %s created.\" % module.params['license_key'])\n\n  elif state == 'absent':\n    # delete the license key\n    id = module.params['license_key']\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(request_data), id=id)\n    try:\n       (rc, resp) = request(manager_url+ '/licenses/' + id, method='DELETE',\n                            url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg=\"Failed to delete license with id %s. Error[%s].\" % (id, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=id, message=\"license with license key %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_licenses_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_licenses_facts\nshort_description: Get all licenses\ndescription: Returns all licenses.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: Get all licenses\n  nsxt_licenses_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils.urls import open_url, fetch_url\nfrom ansible.module_utils._text import to_native\nfrom ansible.module_utils.six.moves.urllib.error import HTTPError\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/licenses', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing licenses. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_local_manager_registration.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2021 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_local_manager_registration\nshort_description: 'Register a local manager with the global manager'\ndescription: \"Registers a local manager with the global manager\"\nversion_added: '3.2'\nauthor: 'Kaushik Lele'\noptions:\n    hostname:\n        description: 'Deployed NSX Global manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    display_name:\n        description: 'Identifier to use when displaying entity in logs or GUI. Defaults to ID if not set'\n        required: false\n        type: str\n    description:\n        description: 'Description of this resource'\n        required: false\n        type: str\n    fail_if_rtt_exceeded:\n        description: 'Fail onboarding if maximum RTT exceeded.'\n        required: false\n        type: bool\n    id:\n        description: 'Unique identifier of this resource'\n        required: true\n        type: str\n    maximum_rtt:\n        description: \"Maximum acceptable packet round trip time (RTT). \n                If provided and fail_if_rtt_exceeded is true, onboarding of the site will\n                fail if measured RTT is greater than this value.\n                Minimum: 0\n                Maximum: 1000\n                Default: 250\"\n        required: false\n        type: int                  \n    site_connection_info:\n        description: Site connecion info (fqdn, password...)\n        fqdn:\n            description: 'IP address or hostname of local manager'\n            required: true\n            type: str\n        password:\n            description: \"Password for the user\"\n            no_log: 'True'\n            required: false\n            type: str\n        required: false\n        thumbprint:\n            description: 'Thumbprint of local manager in the form of a SHA-256 hash represented in lower case HEX'\n            no_log: 'True'\n            required: false\n            type: str\n        username:\n            description: 'Username value of the local manager'\n            required: false\n            type: str\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n\n    \n'''\n\nEXAMPLES = '''\n- name: Register local manager with NSX\n  nsxt_local_manager_registration:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    id: \"LM-Mumbai\"\n    display_name: \"Mumbai LM\"\n    site_connection_info:\n      fqdn: \"10.161.244.213\"\n      username: \"admin\"\n      password: \"Admin!23\"\n      thumbprint: \"31a4eeaef05ad711c84d688cfb72001d17a4965a963611d9af63fb86ff55276cf\"\n    state: present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\nimport ssl\nimport socket\nimport hashlib\n\ndef get_local_manager_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n\n#   site_connection_info is an array\n    args[\"site_connection_info\"] = [args[\"site_connection_info\"]]\n    return args\n\ndef get_local_managers(module, url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(url, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing local manager. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_local_manager_by_id(module, url, mgr_username, mgr_password, validate_certs, id):\n    local_managers = get_local_managers(module, url, mgr_username, mgr_password, validate_certs)\n    for local_manager in local_managers['results']:\n        if local_manager.__contains__('id') and local_manager['id'] == id:\n            return local_manager\n    return None\n\ndef check_for_update(module, url, mgr_username, mgr_password, validate_certs, local_manager_params):\n    existing_local_manager = get_local_manager_by_id(module, url, mgr_username, mgr_password, validate_certs, local_manager_params['id'])\n    if existing_local_manager is None:\n        return False\n    if existing_local_manager['site_connection_info'][0]['fqdn'] != local_manager_params['site_connection_info'][0]['fqdn'] or \\\n        existing_local_manager['site_connection_info'][0]['thumbprint'] != local_manager_params['site_connection_info'][0]['thumbprint'] :\n        return True\n    return False\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                        id=dict(required=True, type='str'),\n                        site_connection_info=dict(required=False, type='dict', no_log=True,\n                        username=dict(required=False, type='str'),\n                        password=dict(required=False, type='str'),\n                        thumbprint=dict(required=False, type='str'),\n                        fqdn=dict(required=True, type='str')),\n                        fail_if_rtt_exceeded=dict(required=False, type='bool'),\n                        maximum_rtt=dict(required=False, type='int'),\n                        state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  local_manager_params = get_local_manager_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  id = module.params['id']\n  manager_url = 'https://{}/global-manager/api/v1'.format(mgr_hostname)\n  sites_api_url = manager_url + '/global-infra/sites/'\n  local_manager_dict = get_local_manager_by_id (module, sites_api_url, mgr_username, mgr_password, validate_certs, id)\n  local_manager_id, revision = None, None\n  if local_manager_dict:\n    local_manager_id = local_manager_dict['id']\n    revision = local_manager_dict['_revision']\n\n  if state == 'present':\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n    updated = check_for_update(module, sites_api_url, mgr_username, mgr_password, validate_certs, local_manager_params)\n    if not updated:\n      # add the local_manager\n      request_data = json.dumps(local_manager_params)\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(request_data), id='12345')\n      try:\n          if local_manager_id:\n              module.exit_json(changed=False, id=local_manager_id, message=\"Local manager with id %s already exist.\"% module.params['id'])\n\n          (rc, resp) = request(sites_api_url + '%s' % module.params['id'], data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n                module.fail_json(msg=\"Failed to add local_manager. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      module.exit_json(changed=True, id=None, body= str(resp), message=\"Local manager with id %s created.\" % module.params['id'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(local_manager_params)), id=local_manager_id)\n      local_manager_params['_revision'] = revision # update current revision\n      request_data = json.dumps(local_manager_params)\n      id = local_manager_id\n      try:\n          (rc, resp) = request(sites_api_url + '%s' % id, data=request_data, headers=headers, method='PATCH',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update local_manager with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n      module.exit_json(changed=True, id=None, body= str(resp), message=\"Local manager with id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = local_manager_id\n    if id is None:\n        module.exit_json(changed=False, msg='No local manager exist with id %s' % id)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(local_manager_params)), id=id)\n    try:\n        (rc, resp) = request(sites_api_url + \"%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete local manager with id %s. Error[%s].\" % (id, to_native(err)))\n\n    module.exit_json(changed=True, id=id, message=\"Local manager with id %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_local_managers_compatibility.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2021 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_local_managers_compatibility\nshort_description: 'Checks the compatibility of a local manager for registration with a global manager'\ndescription: \"Checks the compatibility of a local manager for registration with a global manager\"\nversion_added: '3.2'\nauthor: 'Kaushik Lele'\noptions:\n    hostname:\n        description: 'Deployed NSX Global manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    site_connection_info:\n        description: 'Site Connection ofno (fqdn, password...'\n        fqdn:\n            description: 'IP address or hostname of local manager'\n            required: true\n            type: str\n        password:\n            description: \"Password for the user\"\n            no_log: 'True'\n            required: false\n            type: str\n        required: false\n        thumbprint:\n            description: 'Thumbprint of local manager in the form of a SHA-256 hash represented in lower case HEX'\n            no_log: 'True'\n            required: false\n            type: str\n        username:\n            description: 'Username value of the local manager'\n            required: false\n            type: str   \n'''\n\nEXAMPLES = '''\n- name: Checks the compatibility of a local manager for registration with a global manager\n  nsxt_local_managers_compatibility:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    site_connection_info:\n      fqdn: \"10.161.244.213\"\n      username: \"admin\"\n      password: \"Admin!23\"\n      thumbprint: \"1a4eeaef05ad711c84d688cfb72001d17a4965a963611d9af63fb86ff55276cf\"\n'''\n\nRETURN = '''\nversion_compatible:\n    description: Specifies whether local manager version is compatible with global manager.\n    type: bool\n    returned: when API invocation is successful\n'''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\nimport ssl\nimport socket\nimport hashlib\n\ndef get_local_manager_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n\n    return args\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(site_connection_info=dict(required=False, type='dict', no_log=True,\n                    username=dict(required=False, type='str'),\n                    password=dict(required=False, type='str'),\n                    thumbprint=dict(required=False, type='str'),\n                    fqdn=dict(required=True, type='str')))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  local_manager_params = get_local_manager_params(module.params.copy())\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  manager_url = 'https://{}/global-manager/api/v1'.format(mgr_hostname)\n  check_copmatibility_api_url = manager_url + '/global-infra/onboarding-check-compatibility'\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n\n\n  request_data = json.dumps(local_manager_params['site_connection_info'])\n  try:\n    (rc, resp) = request(check_copmatibility_api_url, data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing local manager. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=False, **resp)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_local_managers_facts.py",
    "content": "#!/usr/bin/python\n#\n# Copyright 2021 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_local_managers_facts\nshort_description: 'Return the list of local managers registered with the global manager'\ndescription: \"Return the list of local managers registered with the global manager\"\nversion_added: '3.2'\nauthor: 'Kaushik Lele'\noptions:\n    hostname:\n        description: 'Deployed NSX Global manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n\n\n    \n'''\n\nEXAMPLES = '''\n- name: Register local manager with NSX\n  nsxt_local_managers_facts:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\nimport ssl\nimport socket\nimport hashlib\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  manager_url = 'https://{}/global-manager/api/v1'.format(mgr_hostname)\n  sites_api_url = manager_url + '/global-infra/sites/'\n\n  changed = False\n  try:\n    (rc, resp) = request(sites_api_url, headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing local managers. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_logical_ports.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_logical_ports\nshort_description: Create a Logical Port\ndescription: \"Creates a new logical switch port. The required parameters are the\nassociated logical_switch_id and admin_state (UP or DOWN). Optional\nparameters are the attachment and switching_profile_ids. If you don't\nspecify switching_profile_ids, default switching profiles are assigned to\nthe port. If you don't specify an attachment, the switch port remains\nempty. To configure an attachment, you must specify an id, and\noptionally you can specify an attachment_type (VIF or LOGICALROUTER).\nThe attachment_type is VIF by default.\"\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n    address_bindings:\n        description: 'Address bindings for logical port'\n        required: false\n        type: array of PacketAddressClassifier\n    admin_state:\n        description: Represents Desired state of the logical port\n        required: true\n        type: str\n    attachment:\n        attachment_type:\n            description: Indicates the type of logical port attachment. By default it is Virtual\n                         Machine interface (VIF)\n            required: false\n            type: str\n        context:\n            allocate_addresses:\n                description: \"A flag to indicate whether to allocate addresses from allocation\n                              pools bound to the parent logical switch.\"\n                required: false\n                type: str\n            app_id:\n                description: \"An application ID used to identify / look up a child VIF\n                              behind a parent VIF. Only effective when vif_type is CHILD.\"\n                required: false\n                type: str\n            description: Attachment Context\n            parent_vif_id:\n                description: VIF ID of the parent VIF if vif_type is CHILD\n                required: false\n                type: str\n            required: false\n            resource_type:\n                description: \"The type of this resource\"\n                required: true\n                type: str\n            traffic_tag:\n                description: \"Current we use VLAN id as the traffic tag.\n                              Only effective when vif_type is CHILD.\n                              Each logical port inside a container must have a\n                              unique traffic tag. If the traffic_tag is not\n                              unique, no error is generated, but traffic will\n                              not be delivered to any port with a non-unique tag.\"\n                required: false\n                type: int\n            transport_node_name:\n                description: name of the transport node that observed a traceflow packet\n                required: false\n                type: str\n            tunnel_id:\n                description: Tunnel Id to uniquely identify the extension.\n                required: true\n                type: int\n            type: dict\n            vif_type:\n                description: Type of the VIF attached to logical port\n                required: true\n                type: str\n        description: Logical port attachment\n        id:\n            description: unique id\n            required: true\n            type: str\n        required: false\n        type: dict\n    display_name:\n        description: Display name\n        required: true\n        type: str\n    extra_configs:\n        description: 'This property could be used for vendor specific configuration in key\n                      value string pairs. Logical port setting will override logical switch\n                      setting if the same key was set on both logical switch and logical port.'\n        required: false\n        type: array of ExtraConfig\n    ignore_address_bindings:\n        description: 'IP Discovery module uses various mechanisms to discover address\n                      bindings being used on each port. If a user would like to ignore\n                      any specific discovered address bindings or prevent the discovery\n                      of a particular set of discovered bindings, then those address\n                      bindings can be provided here. Currently IP range in CIDR format\n                      is not supported.'\n        required: false\n        type: array of PacketAddressClassifier\n    init_state:\n        description: 'Set initial state when a new logical port is created. ''UNBLOCKED_VLAN''\n                      means new port will be unblocked on traffic in creation, also VLAN will\n                      be set with corresponding logical switch setting.'\n        required: false\n        type: str\n    logical_switch_name:\n        description: Name of logical Switch\n        required: true\n        type: str\n    description:\n        description: 'Description of the resource'\n        required: false\n        type: str\n    tags:\n        description: 'Opaque identifiers meaningful to the API user'\n        required: false\n        type: str\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'. \n                     'present' is used to create or update resource. \n                     'absent' is used to delete resource.\"\n        required: true\n    switching_profiles:\n        description: List of Switching Profiles name and type\n        required: false\n        type: list \n'''\n\nEXAMPLES = '''\n- name: Create a Logical Port\n  nsxt_logical_ports:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      logical_switch_name: LS1\n      attachment:\n        attachment_type: VIF\n        id: vif1\n      admin_state: UP\n      state: \"present\"\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\n\ndef get_logical_port_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_logical_ports(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/logical-ports', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing logical ports. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_logical_port_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    logical_ports = get_logical_ports(module, manager_url, mgr_username, mgr_password, validate_certs)\n    if logical_ports and len(logical_ports['results'])>0:\n        for logical_port in logical_ports['results']:\n            if logical_port.__contains__('display_name') and logical_port['display_name'] == display_name:\n                return logical_port\n    return None\n\ndef get_transport_nodes(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/transport-nodes', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing transport nodes. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_tn_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    transport_nodes = get_transport_nodes(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for transport_node in transport_nodes['results']:\n        if transport_node.__contains__('display_name') and transport_node['display_name'] == display_name:\n            return transport_node\n    return None\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['id']\n    module.fail_json(msg='No id exists with display name %s' % display_name)\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, logical_port_params ):\n    logical_port_params['logical_switch_id'] = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                            '/logical-switches', logical_port_params.pop('logical_switch_name', None))\n    host_switch_profile_ids = []\n    host_switch_profiles = logical_port_params.pop('switching_profiles', None)\n    if host_switch_profiles:\n        for host_switch_profile in host_switch_profiles:\n            profile_obj = {}\n            profile_obj['value'] = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                                    \"/switching-profiles\", host_switch_profile['name'])\n            profile_obj['key'] = host_switch_profile['type']\n            host_switch_profile_ids.append(profile_obj)\n    logical_port_params['switching_profile_ids'] = host_switch_profile_ids\n\n    if logical_port_params.__contains__('attachment') and logical_port_params['attachment'].__contains__('context') and \\\n        logical_port_params['attachment']['context'].__contains__('transport_node_name'):\n        logical_port_params['attachment']['context']['transport_node_uuid'] = get_id_from_display_name(module, manager_url, mgr_username, mgr_password,\n                validate_certs, '/transport-nodes', logical_port_params['attachment']['context']['transport_node_name'])\n    return logical_port_params\n\n# def ordered(obj):\n#     if isinstance(obj, dict):\n#         return sorted((k, ordered(v)) for k, v in obj.items())\n#     if isinstance(obj, list):\n#         return sorted(ordered(x) for x in obj)\n#     else:\n#         return obj\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, logical_port_with_ids):\n    existing_logical_port = get_logical_port_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, logical_port_with_ids['display_name'])\n    if existing_logical_port is None:\n        return False\n    if existing_logical_port.__contains__('attachment') and existing_logical_port['attachment'].__contains__('attachment_type') and \\\n        logical_port_with_ids.__contains__('attachment') and logical_port_with_ids['attachment'].__contains__('attachment_type') and \\\n        (existing_logical_port['attachment']['attachment_type'] != logical_port_with_ids['attachment']['attachment_type'] or \\\n        existing_logical_port['attachment']['id'] != logical_port_with_ids['attachment']['id']):\n        return True\n    if existing_logical_port.__contains__('switching_profile_ids') and logical_port_with_ids.__contains__('switching_profile_ids') and \\\n        existing_logical_port['switching_profile_ids'] != logical_port_with_ids['switching_profile_ids']:\n        return True\n    if existing_logical_port['admin_state'] != logical_port_with_ids['admin_state']:\n        return True\n    return False\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                        logical_switch_name=dict(required=True, type='str'),\n                        init_state=dict(required=False, type='str'),\n                        switching_profiles=dict(required=False, type='list'),\n                        attachment=dict(required=False, type='dict',\n                        attachment_type=dict(required=False, type='str'),\n                        context=dict(required=False, type='dict',\n                        tunnel_id=dict(required=True, type='int'),\n                        vif_type=dict(required=True, type='str'),\n                        parent_vif_id=dict(required=False, type='str'),\n                        traffic_tag=dict(required=False, type='int'),\n                        app_id=dict(required=False, type='str'),\n                        allocate_addresses=dict(required=False, type='str'),\n                        resource_type=dict(required=True, type='str'),\n                        transport_node_name=dict(required=False, type='str')),\n                        id=dict(required=True, type='str')),\n                        admin_state=dict(required=True, type='str'),\n                        extra_configs=dict(required=False, type='list'),\n                        address_bindings=dict(required=False, type='list'),\n                        ignore_address_bindings=dict(required=False, type='list'),\n                        description=dict(required=False, type='str'),\n                        tags=dict(required=False, type='list'),\n                        state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  logical_port_params = get_logical_port_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  lport_dict = get_logical_port_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  lport_id, revision = None, None\n  if lport_dict:\n    lport_id = lport_dict['id']\n    revision = lport_dict['_revision']\n\n  if state == 'present':\n    body = update_params_with_id(module, manager_url, mgr_username, mgr_password, validate_certs, logical_port_params)\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, body)\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n\n    if not updated:\n      # add the logical_port\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(body)), id='12345')\n      request_data = json.dumps(body)\n      try:\n          if lport_id:\n              module.exit_json(changed=False, id=lport_id, message=\"Logical port with display_name %s already exist\"% module.params['display_name'])\n\n          (rc, resp) = request(manager_url+ '/logical-ports', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to add logical port. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"Logical port with displayname %s created.\" % module.params['display_name'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(body)), id=lport_id)\n      body['_revision'] = revision # update current revision\n      request_data = json.dumps(body)\n      id = lport_id\n      try:\n          (rc, resp) = request(manager_url+ '/logical-ports/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update logical port with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"logical port with id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = lport_id\n    if id is None:\n        module.exit_json(changed=False, msg='No logical port exist with display name %s' % display_name)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(logical_port_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/logical-ports/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete logical port with id %s. Error[%s].\" % (id, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=id, message=\"Logical port with id %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_logical_ports_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_logical_ports_facts\nshort_description: List All Logical Ports\ndescription: Returns information about all configured logical switch ports. Logical\n             switch ports connect to VM virtual network interface cards (NICs). Each\n             logical port is associated with one logical switch.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: List All Logical Ports\n  nsxt_logical_ports_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils.urls import open_url, fetch_url\nfrom ansible.module_utils._text import to_native\nfrom ansible.module_utils.six.moves.urllib.error import HTTPError\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/logical-ports', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing list of logical ports. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_logical_router_ports.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_logical_router_ports\nshort_description: Create a Logical Router Port\ndescription: \"Creates a logical router port. The required parameters include resource_type\n(LogicalRouterUpLinkPort, LogicalRouterDownLinkPort, LogicalRouterLinkPort,\nLogicalRouterLoopbackPort, LogicalRouterCentralizedServicePort); and\nlogical_router_id (the router to which each logical router port is assigned).\nThe service_bindings parameter is optional.\"\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n    admin_state:\n        description: Admin state of port.\n        required: false\n        type: str\n    display_name:\n        description: Display name\n        required: true\n        type: str\n    edge_cluster_member_index:\n        description: Member index of the edge node on the cluster\n        required: false\n        type: list\n    enable_netx:\n        description: Port is exclusively used for N-S service insertion\n        required: false\n        type: boolean\n    linked_logical_router_port_id:\n        description: Identifier of connected LogicalRouterLinkPortOnTIER1 of TIER1 logical\n                     router\n        is_valid:\n            description: Will be set to false if the referenced NSX resource has been deleted.\n            required: false\n            type: boolean\n        profile_type:\n            description: Profile type of the ServiceConfig\n            required: true\n            type: str\n        required: false\n        selected:\n            description: Set to true if this resource has been selected to be acted upon\n            required: true\n            type: boolean\n        service:\n            alg:\n                description: \"The Application Layer Gateway (ALG) protocol.\n                              Please note, protocol NBNS_BROADCAST and NBDG_BROADCAST are  \n                              deprecated.Please use UDP protocol and create L4 Port Set type \n                              of service instead.\"\n                required: true\n                type: str\n            description: Service which registered the ip.\n            destination_ports:\n                description: Destination ports\n                required: false\n                type: list\n            ether_type:\n                description: Type of the encapsulated protocol\n                required: true\n                type: int\n            icmp_code:\n                description: 'Code of the IPv4 ICMP message.'\n                required: false\n                type: int\n            icmp_type:\n                description: ICMP message type\n                required: false\n                type: int\n            l4_protocol:\n                description: L4 protocol\n                required: true\n                type: str\n            protocol:\n                description: Export protocol\n                required: true\n                type: str\n            protocol_number:\n                description: The IP protocol number\n                required: true\n                type: int\n            required: false\n            resource_type:\n                description: \"LogicalRouterUpLinkPort is allowed only on TIER0 logical router.\n                              It is the north facing port of the logical router. \n                              LogicalRouterLinkPortOnTIER0 is allowed only on TIER0 logical \n                              router.\n                              This is the port where the LogicalRouterLinkPortOnTIER1\n                              of TIER1 logical router connects to. LogicalRouterLinkPortOnTIER1\n                              is allowed only on TIER1 logical router.\n                              This is the port using which the user connected to TIER1 logical\n                              router for upwards connectivity via TIER0 logical router.\n\n                              Connect this port to the LogicalRouterLinkPortOnTIER0 of the TIER0\n                              logical router. LogicalRouterDownLinkPort is for the connected \n                              subnets on the logical router. LogicalRouterLoopbackPort is a \n                              loopback port for logical router component which is placed on c\n                              hosen edge cluster member. LogicalRouterIPTunnelPort is a IPSec VPN\n                              tunnel port created on logical router when route based VPN session \n                              configured.\n                              LogicalRouterCentralizedServicePort is allowed only on Active/Standby \n                              TIER0 and TIER1 logical router. Port can be connected to VLAN or \n                              overlay logical switch. Unlike downlink port it does not participate\n                              in distributed routing and hosted on all edge cluster members \n                              associated with logical router.\n                              Stateful services can be applied on this port.\"\n                required: true\n                type: str\n            source_ports:\n                description: Source ports\n                required: false\n                type: list\n            type: dict\n        target_display_name:\n            description: Display name of the NSX resource.\n            required: false\n            type: str\n        target_id:\n            description: Identifier of the NSX resource.\n            required: false\n            type: str\n        target_type:\n            description: Type of the Policy object corresponding to the source type (e.g. Segment).\n            required: false\n            type: str\n        type: dict\n    linked_logical_switch_port_id:\n        description: Reference to the logical switch port to connect to\n        is_valid:\n            description: Will be set to false if the referenced NSX resource has been deleted.\n            required: false\n            type: boolean\n        profile_type:\n            description: Profile type of the ServiceConfig\n            required: true\n            type: str\n        required: false\n        selected:\n            description: Set to true if this resource has been selected to be acted upon\n            required: true\n            type: boolean\n        service:\n            alg:\n                description: \"The Application Layer Gateway (ALG) protocol.\n                              Please note, protocol NBNS_BROADCAST and \n                              NBDG_BROADCAST are  deprecated.\n                              Please use UDP protocol and create L4 Port \n                              Set type of service instead.\"\n                required: true\n                type: str\n            description: Service which registered the ip.\n            destination_ports:\n                description: Destination ports\n                required: false\n                type: list\n            ether_type:\n                description: Type of the encapsulated protocol\n                required: true\n                type: int\n            icmp_code:\n                description: 'Code of the IPv4 ICMP message.'\n                required: false\n                type: int\n            icmp_type:\n                description: ICMP Type\n                required: false\n                type: int\n            l4_protocol:\n                description: L4 Protocol\n                required: true\n                type: str\n            protocol:\n                description: Export protocol\n                required: true\n                type: str\n            protocol_number:\n                description: The IP protocol number\n                required: true\n                type: int\n            required: false\n            resource_type:\n                description: \"LogicalRouterUpLinkPort is allowed only on TIER0 logical router.\n                              It is the north facing port of the logical router. \n                              LogicalRouterLinkPortOnTIER0 is allowed only on TIER0 logical \n                              router.\n                              This is the port where the LogicalRouterLinkPortOnTIER1\n                              of TIER1 logical router connects to. LogicalRouterLinkPortOnTIER1\n                              is allowed only on TIER1 logical router.\n                              This is the port using which the user connected to TIER1 logical\n                              router for upwards connectivity via TIER0 logical router.\n\n                              Connect this port to the LogicalRouterLinkPortOnTIER0 of the TIER0\n                              logical router. LogicalRouterDownLinkPort is for the connected \n                              subnets on the logical router. LogicalRouterLoopbackPort is a \n                              loopback port for logical router component which is placed on c\n                              hosen edge cluster member. LogicalRouterIPTunnelPort is a IPSec VPN\n                              tunnel port created on logical router when route based VPN session \n                              configured.\n                              LogicalRouterCentralizedServicePort is allowed only on Active/Standby \n                              TIER0 and TIER1 logical router. Port can be connected to VLAN or \n                              overlay logical switch. Unlike downlink port it does not participate\n                              in distributed routing and hosted on all edge cluster members \n                              associated with logical router.\n                              Stateful services can be applied on this port.\"\n                required: true\n                type: str\n            source_ports:\n                description: Source ports\n                required: false\n                type: list\n            type: dict\n        target_display_name:\n            description: Display name of the NSX resource.\n            required: false\n            type: str\n        target_id:\n            description: Identifier of the NSX resource.\n            required: false\n            type: str\n        target_type:\n            description: Type of the Policy object corresponding to the source type \n                         (e.g. Segment).\n            required: false\n            type: str\n        type: dict\n    logical_router_name:\n        description: Name of the logical router\n        required: true\n        type: str\n    mac_address:\n        description: MAC address\n        required: false\n        type: str\n    mtu:\n        description: 'Maximum transmission unit specifies the size of the largest packet\n                      that a network protocol can transmit. If not specified, the global logical\n                      MTU set in the /api/v1/global-configs/RoutingGlobalConfig API will be\n                      used.'\n        required: false\n        type: int\n    resource_type:\n        description: \"LogicalRouterUpLinkPort is allowed only on TIER0 logical router.\n                    It is the north facing port of the logical router. \n                    LogicalRouterLinkPortOnTIER0 is allowed only on TIER0 logical \n                    router.\n                    This is the port where the LogicalRouterLinkPortOnTIER1\n                    of TIER1 logical router connects to. LogicalRouterLinkPortOnTIER1\n                    is allowed only on TIER1 logical router.\n                    This is the port using which the user connected to TIER1 logical\n                    router for upwards connectivity via TIER0 logical router.\n\n                    Connect this port to the LogicalRouterLinkPortOnTIER0 of the TIER0\n                    logical router. LogicalRouterDownLinkPort is for the connected \n                    subnets on the logical router. LogicalRouterLoopbackPort is a \n                    loopback port for logical router component which is placed on c\n                    hosen edge cluster member. LogicalRouterIPTunnelPort is a IPSec VPN\n                    tunnel port created on logical router when route based VPN session \n                    configured.\n                    LogicalRouterCentralizedServicePort is allowed only on Active/Standby \n                    TIER0 and TIER1 logical router. Port can be connected to VLAN or \n                    overlay logical switch. Unlike downlink port it does not participate\n                    in distributed routing and hosted on all edge cluster members \n                    associated with logical router.\n                    Stateful services can be applied on this port.\"\n        required: true\n        type: str\n    service_bindings:\n        description: Service Bindings\n        required: false\n        type: array of ServiceBinding\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'. \n                      'present' is used to create or update resource. \n                      'absent' is used to delete resource.\"\n        required: true\n    subnets:\n        description: Logical router port subnets\n        required: false\n        type: array of IPSubnet\n    urpf_mode:\n        description: Unicast Reverse Path Forwarding mode\n        required: false\n        type: str\n    vpn_session_id:\n        description: Associated VPN session identifier.\n        required: false\n        type: str\n    description:\n        description: Description of the resou\n        required: False\n        type: 'str'\n    ndra_profile_id:\n        description: NDRA Profile id\n        required: False\n        type: 'str'\n    enable_multicast:\n        description: Flag to enable/disable Multicast\n        required: False\n        type: 'bool'\n    routing_policies:\n        description: Routing policies used to specify how the traffic, which matches the\n                     policy routes, will be processed.\n        required: False\n        type: 'list'\n    ndra_prefix_config:\n        description: Configuration to override the neighbor discovery router advertisement\n                      prefix time parameters at the subnet level. Note that users are allowed\n                      to override the prefix time only for IPv6 subnets which are configured\n                      on the port.\n        required: False\n        type: 'list'\n    pim_config:\n        description: PIM configuration parameters\n        required: False\n        type: 'dict'\n        enabled:\n            description: Flag to enable/disable PIM\n            required: False\n            type: 'bool'\n            default: False\n    tags:\n        description: Opaque identifiers meaningful to the API user\n        required: False\n        type: list\n    \n'''\n\nEXAMPLES = '''\n- name: Create a Logical Router Port\n  nsxt_logical_routers_ports:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      resource_type: LogicalRouterDownLinkPort\n      logical_router_name: \"lr-1\"\n      linked_logical_switch_port_id:\n        target_type: LogicalPort\n        target_id: \"18691381-b08f-4d90-8c0c-98d0e449b141\"\n      subnets:\n      - ip_addresses:\n        - \"172.16.40.1\"\n        prefix_length: 24\n      state: present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef get_logical_router_port_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_logical_router_ports(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/logical-router-ports', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing logical router ports. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_lr_port_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    logical_router_ports = get_logical_router_ports(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for logical_router_port in logical_router_ports['results']:\n        if logical_router_port.__contains__('display_name') and logical_router_port['display_name'] == display_name:\n            return logical_router_port\n    return None\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name, exit_if_not_found=True):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['id']\n    if exit_if_not_found:\n        module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_port_params ):\n    logical_router_port_params['logical_router_id'] = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                '/logical-routers', logical_router_port_params.pop('logical_router_name', None))\n    if logical_router_port_params.__contains__('linked_logical_switch_port_id') and \\\n        logical_router_port_params['linked_logical_switch_port_id'].__contains__('target_display_name'):\n        if not logical_router_port_params['linked_logical_switch_port_id'].__contains__('target_id'):\n            logical_router_port_params['linked_logical_switch_port_id']['target_id'] = get_id_from_display_name(module, manager_url, mgr_username,\n                  mgr_password, validate_certs, '/logical-ports', logical_router_port_params['linked_logical_switch_port_id']['target_display_name'])\n    return logical_router_port_params\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_port_params):\n    existing_lr_port = get_lr_port_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_port_params['display_name'])\n    if existing_lr_port is None:\n        return False\n    if existing_lr_port.__contains__('description') and logical_router_port_params.__contains__('description') and\\\n       existing_lr_port['description'] != logical_router_port_params['description']:\n       return True\n    if existing_lr_port.__contains__('description') and not logical_router_port_params.__contains__('description'):\n        return True\n    if not existing_lr_port.__contains__('description') and logical_router_port_params.__contains__('description'):\n        return True\n    if existing_lr_port['resource_type'] != logical_router_port_params['resource_type']:\n        return True\n    if existing_lr_port['logical_router_id'] != logical_router_port_params['logical_router_id']:\n        return True\n    if existing_lr_port.__contains__('service_bindings') and logical_router_port_params.__contains__('service_bindings') and \\\n        existing_lr_port['service_bindings'] != logical_router_port_params['service_bindings']:\n        return True\n    if existing_lr_port.__contains__('subnets') and logical_router_port_params.__contains__('subnets') and \\\n        existing_lr_port['subnets'] != logical_router_port_params['subnets']:\n        return True\n    return False\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                        description=dict(required=False, type='str'),\n                        ndra_profile_id=dict(required=False, type='str'),\n                        enable_multicast=dict(required=False, type='bool'),\n                        routing_policies=dict(required=False, type='list'),\n                        ndra_prefix_config=dict(required=False, type='list'),\n                        pim_config=dict(required=False, type='dict',\n                        enabled=dict(required=False, type='bool', default=False)),\n                        subnets=dict(required=False, type='list'),\n                        urpf_mode=dict(required=False, type='str'),\n                        mac_address=dict(required=False, type='str'),\n                        linked_logical_switch_port_id=dict(required=False, type='dict',\n                        profile_type=dict(required=True, type='str'),\n                        selected=dict(required=True, type='bool'),\n                        service=dict(required=False, type='dict',\n                        ether_type=dict(required=True, type='int'),\n                        destination_ports=dict(required=False, type='list'),\n                        l4_protocol=dict(required=True, type='str'),\n                        source_ports=dict(required=False, type='list'),\n                        icmp_code=dict(required=False, type='int'),\n                        icmp_type=dict(required=False, type='int'),\n                        protocol=dict(required=True, type='str'),\n                        protocol_number=dict(required=True, type='int'),\n                        alg=dict(required=True, type='str'),\n                        resource_type=dict(required=True, type='str')),\n                        target_display_name=dict(required=False, type='str'),\n                        is_valid=dict(required=False, type='bool'),\n                        target_id=dict(required=False, type='str'),\n                        target_type=dict(required=False, type='str')),\n                        admin_state=dict(required=False, type='str'),\n                        vpn_session_id=dict(required=False, type='str'),\n                        enable_netx=dict(required=False, type='bool'),\n                        edge_cluster_member_index=dict(required=False, type='list'),\n                        mtu=dict(required=False, type='int'),\n                        linked_logical_router_port_id=dict(required=False, type='dict',\n                        profile_type=dict(required=True, type='str'),\n                        selected=dict(required=True, type='bool'),\n                        service=dict(required=False, type='dict',\n                        ether_type=dict(required=True, type='int'),\n                        destination_ports=dict(required=False, type='list'),\n                        l4_protocol=dict(required=True, type='str'),\n                        source_ports=dict(required=False, type='list'),\n                        icmp_code=dict(required=False, type='int'),\n                        icmp_type=dict(required=False, type='int'),\n                        protocol=dict(required=True, type='str'),\n                        protocol_number=dict(required=True, type='int'),\n                        alg=dict(required=True, type='str'),\n                        resource_type=dict(required=True, type='str')),\n                        target_display_name=dict(required=False, type='str'),\n                        is_valid=dict(required=False, type='bool'),\n                        target_id=dict(required=False, type='str'),\n                        target_type=dict(required=False, type='str')),\n                        logical_router_name=dict(required=True, type='str'),\n                        service_bindings=dict(required=False, type='list'),\n                        resource_type=dict(required=True, type='str'),\n                        tags=dict(required=False, type='list'),\n                        state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  logical_router_port_params = get_logical_router_port_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  logical_router_port_dict = get_lr_port_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  logical_router_port_id, revision = None, None\n  if logical_router_port_dict:\n    logical_router_port_id = logical_router_port_dict['id']\n    revision = logical_router_port_dict['_revision']\n\n  if state == 'present':\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n    body = update_params_with_id(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_port_params)\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, body)\n\n    if not updated:\n      # add the logical_router_port\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(logical_router_port_params)), id='12345')\n      request_data = json.dumps(logical_router_port_params)\n      try:\n          if logical_router_port_id:\n              module.exit_json(changed=False, id=logical_router_port_id, message=\"Logical router port with display_name %s already exist.\"% module.params['display_name'])\n\n          (rc, resp) = request(manager_url+ '/logical-router-ports', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to add logical router port. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"Logical router port with displayname %s created.\" % module.params['display_name'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(logical_router_port_params)), id=logical_router_port_id)\n      logical_router_port_params['_revision'] = revision # update current revision\n      request_data = json.dumps(logical_router_port_params)\n      id = logical_router_port_id\n      try:\n          (rc, resp) = request(manager_url+ '/logical-router-ports/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update logical router port with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"logical router port with id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = logical_router_port_id\n    if id is None:\n        module.exit_json(changed=False, msg='No logical router port exist with display name %s' % display_name)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(logical_router_port_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/logical-router-ports/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete logical router port with id %s. Error[%s].\" % (id, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=id, message=\"Logical router port with id %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_logical_router_ports_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_logical_router_ports_facts\nshort_description: List Logical Router Ports\ndescription: Returns information about all logical router ports. Information includes the\n              resource_type (LogicalRouterUpLinkPort, LogicalRouterDownLinkPort,\n              LogicalRouterLinkPort, LogicalRouterLoopbackPort, \n              LogicalRouterCentralizedServicePort);\n              logical_router_id (the router to which each logical router port is assigned);\n              and any service_bindings (such as DHCP relay service).\n              The GET request can include a query parameter (logical_router_id\n              or logical_switch_id).\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: List Logical Router Ports\n  nsxt_logical_router_ports_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/logical-router-ports', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing list of logical ports. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_logical_router_static_routes.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_logical_router_static_routes\nshort_description: Add Static Routes on a Logical Router\ndescription: Add Static Routes on a Logical Router\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n    id:\n        description: unique id\n        required: false\n        type: str\n    display_name:\n        description: Display name of the resource\n        required: True\n        type: str\n    description:\n        description: Description of the resource\n        required: false\n        type: str\n    tags:\n        description: Opaque identifier meaningful to API user\n        required: false\n        type: Array of Tag\n    logical_router_name:\n        description: Name of the logical router\n        required: false\n        type: str\n    network:\n        description: destination in cidr\n        required: true\n        type: str\n    next_hops:\n        description: Next Hops\n        required: true\n        type: array of StaticRouteNextHop\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'. \n                      'present' is used to create or update resource. \n                      'absent' is used to delete resource.\"\n        required: true\n    \n'''\n\nEXAMPLES = '''\n    - name: Add Static Routes on a Logical Router\n      nsxt_logical_router_static_routes:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"static_route\"\n        logical_router_name: \"tier-0\"\n        next_hops:\n        - administrative_distance: '2'\n          ip_address: 192.168.200.253\n        network: 192.168.200.0/24\n        state: \"present\"\n\n\n'''\n\nRETURN = '''# '''\n\n\n\n\n\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef get_body_object(body):\n  if body.__contains__('id'):\n    del body['id']\n  if body.__contains__('logical_router_id'):\n    del body['logical_router_id']\n  return body\n\n\ndef get_logical_router_static_route_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name, exit_if_not_found=True):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['id']\n    if exit_if_not_found:\n        module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_static_route_params ):\n    logical_router_static_route_params['logical_router_id'] = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                '/logical-routers', logical_router_static_route_params.pop('logical_router_name', None))\n    return logical_router_static_route_params\n\ndef get_logical_router_static_routes(module, manager_url, mgr_username, mgr_password, validate_certs,logical_router_id):\n    try:\n      (rc, resp) = request(manager_url+ '/logical-routers/%s/routing/static-routes' % logical_router_id , headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing logical router ports. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_lr_static_route_from_network(module, manager_url, mgr_username, mgr_password, validate_certs, network, logical_router_id):\n    logical_router_st_routes = get_logical_router_static_routes(module, manager_url, mgr_username, mgr_password, validate_certs,logical_router_id)\n    for logical_router_st_route in logical_router_st_routes['results']:\n        if logical_router_st_route.__contains__('network') and logical_router_st_route['network'] == network:\n            return logical_router_st_route\n    return None\n\ndef get_lr_static_route_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_static_route_params):\n  logical_router_static_routes = get_logical_router_static_routes(module, manager_url, mgr_username, mgr_password, validate_certs,logical_router_static_route_params['logical_router_id'])\n  for result in logical_router_static_routes['results']:\n    if result.__contains__('display_name') and result['display_name'] == logical_router_static_route_params['display_name']:\n      return result\n  return None\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_static_route_params):\n  existing_lr_static_route = get_lr_static_route_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_static_route_params)\n  if existing_lr_static_route is None:\n    return False\n  if existing_lr_static_route.__contains__('description') and not logical_router_static_route_params.__contains__('description'):\n    return True\n  if not existing_lr_static_route.__contains__('description') and logical_router_static_route_params.__contains__('description'):\n    return True\n  if existing_lr_static_route.__contains__('description') and logical_router_static_route_params.__contains__('description') and\\\n     existing_lr_static_route['description'] != logical_router_static_route_params['description']:\n    return True\n  if existing_lr_static_route.__contains__('next_hops') and not logical_router_static_route_params.__contains__('next_hops'):\n    return True\n  if not existing_lr_static_route.__contains__('next_hops') and logical_router_static_route_params.__contains__('next_hops'):\n    return True\n  if existing_lr_static_route.__contains__('next_hops') and logical_router_static_route_params.__contains__('next_hops') and\\\n     existing_lr_static_route['next_hops'] != logical_router_static_route_params['next_hops']:\n    return True\n  if existing_lr_static_route.__contains__('network') and not logical_router_static_route_params.__contains__('network'):\n    return True\n  if not existing_lr_static_route.__contains__('network') and logical_router_static_route_params.__contains__('network'):\n    return True\n  if existing_lr_static_route.__contains__('network') and logical_router_static_route_params.__contains__('network') and\\\n     existing_lr_static_route['network'] != logical_router_static_route_params['network']:\n    return True\n  return False\n\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(next_hops=dict(required=True, type='list'),\n                logical_router_name=dict(required=False, type='str'),\n                network=dict(required=True, type='str'),\n                id=dict(required=False, type= 'str'),\n                display_name=dict(required=True, type='str'),\n                description=dict(required=False, type='str'),\n                tags=dict(required=False, type='list'),\n                state=dict(required=True, choices=['present', 'absent']))\n\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  logical_router_static_route_params = get_logical_router_static_route_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n  update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_static_route_params)\n  logical_router_id = logical_router_static_route_params[\"logical_router_id\"]\n  logical_router_static_route_id = get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs,\n    '/logical-routers/' + logical_router_id + '/routing/static-routes', display_name, False)\n  logical_router_static_route = get_lr_static_route_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_static_route_params)\n  if logical_router_static_route:\n    revision = logical_router_static_route['_revision']\n\n  if state == 'present':\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_static_route_params)\n\n    if not updated:\n      # add the logical_router_static_route\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(logical_router_static_route_params)), id='12345')\n      request_data = json.dumps(logical_router_static_route_params)\n      try:\n          if logical_router_static_route_id:\n              module.exit_json(changed=False, id=logical_router_static_route_id, message=\"Logical router static route with network %s already exist.\"% module.params['network'])\n\n          (rc, resp) = request(manager_url+ '/logical-routers/%s/routing/static-routes' % logical_router_id, data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to add logical router port. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"Logical router static route  with network %s created.\" % module.params['network'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(logical_router_static_route_params)), id=logical_router_static_route_id)\n      logical_router_static_route_params['_revision'] = revision # update current revision\n      request_data = json.dumps(logical_router_static_route_params)\n      id = logical_router_static_route_id\n      try:\n          (rc, resp) = request(manager_url+ '/logical-routers/%s/routing/static-routes/%s' % (logical_router_id,id), data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update logical router static route with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"logical router static route  with id %s updated.\" % id)\n\n  elif state == 'absent':\n    if logical_router_static_route_id is None:\n        module.exit_json(changed=False, msg='No logical router static route exist with network %s' % network)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(logical_router_static_route_params)), id=logical_router_static_route_id)\n    try:\n        (rc, resp) = request(manager_url + \"/logical-routers/%s/routing/static-routes/%s\" % (logical_router_id,logical_router_static_route_id), method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete logical static route with id %s. Error[%s].\" % (logical_router_static_route_id, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=logical_router_static_route_id, message=\"Logical router static route with id %s deleted.\" % logical_router_static_route_id)\n\n\n\n\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_logical_routers.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_logical_routers\nshort_description: Create a Logical Router\ndescription: Creates a logical router. The required parameters are router_type (TIER0 or\n             TIER1) and edge_cluster_id (TIER0 only). Optional parameters include\n             internal and external transit network addresses.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n    advanced_config:\n        description: Contains config properties for tier0 routers\n        external_transit_networks:\n            description: CIDR block defining tier0 to tier1 links\n            required: false\n            type: list\n        ha_vip_configs:\n            description: This configuration can be defined only for Active-Standby LogicalRouter\n                          to provide redundancy. For multiple uplink ports, multiple HaVipConfigs \n                          must be defined and each config will pair exactly two uplink ports. \n                          The VIP will move and will always be owned by the Active node. \n                          Note - when HaVipConfig[s] are defined, configuring dynamic-routing is \n                          disallowed.\n            required: false\n            type: array of HaVipConfig\n        internal_routing_network:\n            description: Internal Routing Name\n            required: false\n            type: str\n        internal_transit_networks:\n            description: CIDR block defining service router to distributed router links\n            required: false\n            type: list\n        required: false\n        transport_zone_name:\n            description: Name of transport zone\n            required: false\n            type: str\n        type: dict\n    allocation_profile:\n        allocation_pool:\n            allocation_pool_type:\n                description: Types of logical router allocation pool based on services\n                required: true\n                type: str\n            allocation_size:\n                description: \"To address varied customer performance and scalability \n                              requirements, different sizes for load balancer service are \n                              supported: SMALL, MEDIUM and LARGE, each with its own set of \n                              resource and performance. Specify size of load balancer service\n                              which you will bind to TIER1 router.\"\n                required: true\n                type: str\n            description: \"Logical router allocation can be tracked for specific services and\n                          services may have their own hard limits and allocation sizes. For\n                          example load balancer pool should be specified if load balancer\n                          service will be attached to logical router.\"\n            required: false\n            type: dict\n        description: 'Configurations options to auto allocate edge cluster members for\n                      logical router. Auto allocation is supported only for TIER1 and pick\n                      least utilized member post current assignment for next allocation.'\n        enable_standby_relocation:\n            description: 'Flag to enable the auto-relocation of standby service router running\n                          on edge cluster and node associated with the logical router. Only\n                          manually placed service contexts for tier1 logical routers are\n                          considered for the relocation.'\n            required: false\n            type: boolean\n        required: false\n        type: dict\n    description:\n        description: Description of the resource\n        required: false\n        type: str\n    display_name:\n        description: Display name\n        required: true\n        type: str\n    edge_cluster_member_indices:\n        description: 'For stateful services, the logical router should be associated with\n                      edge cluster. For TIER 1 logical router, for manual placement of\n                      service router within the cluster, edge cluster member indices needs\n                      to be provided else same will be auto-allocated. You can provide\n                      maximum two indices for HA ACTIVE_STANDBY. For TIER0 logical router\n                      this property is no use and placement is derived from logical router\n                      uplink or loopback port.'\n        required: false\n        type: list\n    edge_cluster_name:\n        description: Name of edge cluster\n        required: false\n        type: str\n    failover_mode:\n        description: 'Determines the behavior when a logical router instance restarts after\n                      a failure. If set to PREEMPTIVE, the preferred node will take over,\n                      even if it causes another failure. If set to NON_PREEMPTIVE, then the\n                      instance that restarted will remain secondary.\n                      This property must not be populated unless the high_availability_mode \n                      property is set to ACTIVE_STANDBY.\n                      If high_availability_mode property is set to ACTIVE_STANDBY and this \n                      property is not specified then default will be NON_PREEMPTIVE.'\n        required: false\n        type: str\n    high_availability_mode:\n        description: High availability mode\n        required: false\n        type: str\n    preferred_edge_cluster_member_index:\n        description: Used for tier0 routers only\n        required: false\n        type: int\n    resource_type:\n        choices:\n        - LogicalRouter\n        description: \"A Policy Based VPN requires to define protect rules that match local\n                     and peer subnets. IPSec security associations is negotiated for each pair\n                     of local and peer subnet.\n                     A Route Based VPN is more flexible, more powerful\n                     and recommended over policy based VPN. IP Tunnel port is created and all\n                     traffic routed via tunnel port is protected. Routes can be configured \n                     statically or can be learned through BGP. A route based VPN is must for \n                     establishing redundant VPN session to remote site.\"\n        required: false\n        type: str\n    router_type:\n        description: Type of Logical Router\n        required: true\n        type: str\n    ipv6_profiles:\n        description: IPv6 Profiles\n        required: false\n        type: dict\n        dad_profile_id:\n            description: DAD profile id\n            required: False\n            type: str\n        ndra_profile_id:\n            description: NDRA profile id\n            required: False\n            type: str\n    tags:\n        description: Opaque identifiers meaningful to the API user\n        required: false\n        type: list\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'. \n                      'present' is used to create or update resource. \n                      'absent' is used to delete resource.\"\n        required: true\n    \n'''\n\nEXAMPLES = '''\n- name: Create a Logical Router\n  nsxt_logical_routers:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      resource_type: LogicalRouter\n      description: \"Router West\"\n      display_name: \"tier-0\"\n      edge_cluster_name: edge-cluster-1\n      router_type: TIER0\n      high_availability_mode: ACTIVE_ACTIVE\n      state: present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef get_logical_router_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_logical_routers(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/logical-routers', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing logical routers. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_lr_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    logical_routers = get_logical_routers(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for logical_router in logical_routers['results']:\n        if logical_router.__contains__('display_name') and logical_router['display_name'] == display_name:\n            return logical_router\n    return None\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['id']\n    module.fail_json(msg='No id exists with display name %s' % display_name)\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_params ):\n\n    if logical_router_params.__contains__('edge_cluster_name'):\n        edge_cluster_name = logical_router_params.pop('edge_cluster_name', None)\n        logical_router_params['edge_cluster_id'] = get_id_from_display_name (module, manager_url,\n                                                                                mgr_username, mgr_password, validate_certs,\n                                                                                \"/edge-clusters\", edge_cluster_name)\n    if logical_router_params.__contains__('ipv6_profiles'):\n        if logical_router_params['ipv6_profiles'].__contains__('dad_profile_name'):\n            dad_profile_name = logical_router_params['ipv6_profiles'].pop('dad_profile_name')\n            logical_router_params['ipv6_profiles']['dad_profile_id'] = get_id_from_display_name (module, manager_url,\n                                                                                                   mgr_username, mgr_password, \n                                                                                                   validate_certs,\n                                                                                                   \"/ipv6/dad-profiles\", dad_profile_name)\n        if logical_router_params['ipv6_profiles'].__contains__('ndra_profile_name'):\n            ndra_profile_name = logical_router_params['ipv6_profiles'].pop('ndra_profile_name')\n            logical_router_params['ipv6_profiles']['ndra_profile_id'] = get_id_from_display_name (module, manager_url,\n                                                                                                   mgr_username, mgr_password,\n                                                                                                   validate_certs,\n                                                                                                   \"/ipv6/nd-ra-profiles\",\n                                                                                                  ndra_profile_name)\n    if logical_router_params.__contains__('advanced_config') and logical_router_params['advanced_config'].__contains__('transport_zone_name'):\n        transport_zone_name= logical_router_params['advanced_config'].pop('transport_zone_name', None)\n        logical_router_params['advanced_config']['transport_zone_id'] = get_id_from_display_name (module, manager_url,\n                                                                                mgr_username, mgr_password, validate_certs,\n                                                                                \"/transport-zones\", transport_zone_name)\n\n    if logical_router_params.__contains__('advanced_config') and logical_router_params['advanced_config'].__contains__(\n            'ha_vip_configs'):\n        for i in range(len(logical_router_params['advanced_config']['ha_vip_configs'])):\n            ha_vip_config = logical_router_params['advanced_config']['ha_vip_configs'][i]\n            if ha_vip_config.__contains__('redundant_uplink_port_ids') and ha_vip_config.__contains__(\n                    'redundant_uplink_port_names'):\n                ha_vip_config.pop('redundant_uplink_port_ids', None)\n            if ha_vip_config.__contains__('redundant_uplink_port_ids') and not ha_vip_config.__contains__(\n                    'redundant_uplink_port_names'):\n                continue\n            if not ha_vip_config.__contains__('redundant_uplink_port_ids') and not ha_vip_config.__contains__(\n                    'redundant_uplink_port_names'):\n                continue\n\n            uplink_profiles_names = ha_vip_config['redundant_uplink_port_names']\n            ha_vip_config.pop('redundant_uplink_port_names', None)\n            uplink_profile_ids = get_id_from_display_name_uplink(module, manager_url, mgr_username, mgr_password,\n                                                                 validate_certs,\n                                                                 \"/logical-router-ports\", uplink_profiles_names)\n            ha_vip_config['redundant_uplink_port_ids'] = uplink_profile_ids\n            logical_router_params['advanced_config']['ha_vip_configs'][i] = ha_vip_config\n\n    return logical_router_params\n\n\ndef get_id_from_display_name_uplink(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint,\n                                    uplink_profiles_display_names):\n    uplink_profile_display_name1 = uplink_profiles_display_names[0]\n    uplink_profile_display_name2 = uplink_profiles_display_names[1]\n    try:\n        (rc, resp) = request(manager_url + endpoint, headers=dict(Accept='application/json'),\n                             url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                             ignore_errors=True)\n    except Exception as err:\n        module.fail_json(msg='Error accessing id for uplink display names %s, %s. Error [%s]' % (\n        uplink_profile_display_name1, uplink_profile_display_name2, to_native(err)))\n\n    uplink_profile_ids = []\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and (result['display_name'] == uplink_profile_display_name1 or result[\n            'display_name'] == uplink_profile_display_name2):\n            uplink_profile_ids.append(result['id'])\n    if uplink_profile_ids is None or len(uplink_profile_ids) < 2:\n        module.fail_json(msg='No id exists with uplink display name %s, %s' % (\n        uplink_profile_display_name1, uplink_profile_display_name2))\n    return uplink_profile_ids\n\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_with_ids):\n    existing_logical_router = get_lr_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_with_ids['display_name'])\n    if existing_logical_router is None:\n        return False\n    if existing_logical_router.__contains__('tags') and not logical_router_with_ids.__contains__('tags'):\n        return True\n    if not existing_logical_router.__contains__('tags') and logical_router_with_ids.__contains__('tags'):\n        return True\n    if existing_logical_router.__contains__('tags') and logical_router_with_ids.__contains__('tags') and (\n            not compareTags(existing_logical_router, logical_router_with_ids)):\n        return True\n    if existing_logical_router.__contains__('edge_cluster_id') and logical_router_with_ids.__contains__(\n            'edge_cluster_id') and existing_logical_router['edge_cluster_id'] != logical_router_with_ids[\n        'edge_cluster_id']:\n        return True\n    if existing_logical_router.__contains__('advanced_config') and not logical_router_with_ids.__contains__(\n            'advanced_config'):\n        return True\n    if not existing_logical_router.__contains__('advanced_config') and logical_router_with_ids.__contains__(\n            'advanced_config'):\n        return True\n    if existing_logical_router.__contains__('advanced_config') and logical_router_with_ids.__contains__(\n            'advanced_config') and \\\n            existing_logical_router['advanced_config'].__contains__('ha_vip_configs') and not logical_router_with_ids[\n        'advanced_config'].__contains__('ha_vip_configs'):\n        return True\n    if existing_logical_router.__contains__('advanced_config') and logical_router_with_ids.__contains__(\n            'advanced_config') and not \\\n            existing_logical_router['advanced_config'].__contains__('ha_vip_configs') and logical_router_with_ids[\n        'advanced_config'].__contains__('ha_vip_configs'):\n        return True\n    if existing_logical_router.__contains__('advanced_config') and logical_router_with_ids.__contains__(\n            'advanced_config') and \\\n            existing_logical_router['advanced_config'].__contains__('ha_vip_configs') and logical_router_with_ids[\n        'advanced_config'].__contains__('ha_vip_configs') and \\\n            not checkRedundantUplinkPortIds(existing_logical_router['advanced_config']['ha_vip_configs'],\n                                            logical_router_with_ids['advanced_config']['ha_vip_configs']):\n        return True\n    if existing_logical_router.__contains__('advanced_config') and logical_router_with_ids.__contains__(\n            'advanced_config'):\n        if existing_logical_router['advanced_config'].__contains__('internal_transit_network') and \\\n                logical_router_with_ids['advanced_config'].__contains__('internal_transit_network') and \\\n                existing_logical_router['advanced_config']['internal_transit_network'] != \\\n                logical_router_with_ids['advanced_config']['internal_transit_network']:\n            return True\n        if existing_logical_router['advanced_config'].__contains__('external_transit_networks') and \\\n                logical_router_with_ids['advanced_config'].__contains__('external_transit_networks') and \\\n                existing_logical_router['advanced_config']['external_transit_networks'] != \\\n                logical_router_with_ids['advanced_config']['external_transit_networks']:\n            return True\n        if existing_logical_router['advanced_config'].__contains__('ha_vip_configs') is False and \\\n            logical_router_with_ids['advanced_config'].__contains__('ha_vip_configs') is True:\n            return True\n    return False\n\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                        description=dict(required=False, type='str'),\n                        edge_cluster_member_indices=dict(required=False, type='list'),\n                        allocation_profile=dict(required=False, type='dict',\n                        allocation_pool=dict(required=False, type='dict',\n                        allocation_size=dict(required=True, type='str'),\n                        allocation_pool_type=dict(required=True, type='str')),\n                        enable_standby_relocation=dict(required=False, type='boolean')),\n                        failover_mode=dict(required=False, type='str'),\n                        advanced_config=dict(required=False, type='dict',\n                            transport_zone_name=dict(required=False, type='str'),\n                            internal_transit_networks=dict(required=False, type='list'),\n                            internal_routing_network=dict(required=False, type='str'),\n                            ha_vip_configs=dict(required=False, type='list',\n                                enabled=dict(required=False, type='boolean'),\n                                ha_vip_subnets=dict(required=False, type='list',\n                                    active_vip_addresses=dict(required=False, type='list'),\n                                    prefix_length=dict(required=False, type='str')),\n                                redundant_uplink_port_ids=dict(required=False, type='list'),\n                                redundant_uplink_port_names=dict(required=False,type='list')),\n                            external_transit_networks=dict(required=False, type='list')),\n                        router_type=dict(required=True, type='str'),\n                        preferred_edge_cluster_member_index=dict(required=False, type='int'),\n                        high_availability_mode=dict(required=False, type='str'),\n                        edge_cluster_name=dict(required=False, type='str'),\n                        tags=dict(required=False, type='list'),\n                        ipv6_profiles=dict(required=False, type='dict',\n                        dad_profile_name=dict(required=False, type='str'),\n                        ndra_profile_name=dict(required=False, type='str')),\n                        resource_type=dict(required=False, type='str', choices=['LogicalRouter']),\n                        state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  logical_router_params = get_logical_router_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  logical_router_dict = get_lr_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  logical_router_id, revision = None, None\n  if logical_router_dict:\n    logical_router_id = logical_router_dict['id']\n    revision = logical_router_dict['_revision']\n\n  if state == 'present':\n    body = update_params_with_id(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_params)\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, body)\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n\n    if not updated:\n      # add the router\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(body)), id='12345')\n      request_data = json.dumps(body)\n      try:\n          if logical_router_id:\n              module.exit_json(changed=False, id=logical_router_id, message=\"Logical router with display_name %s already exist.\"% module.params['display_name'])\n\n          (rc, resp) = request(manager_url+ '/logical-routers', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to add logical router. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"Logical router with display_name %s created.\" % module.params['display_name'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(body)), id=logical_router_id)\n\n      body['_revision'] = revision # update current revision\n      request_data = json.dumps(body)\n      id = logical_router_id\n      try:\n          (rc, resp) = request(manager_url+ '/logical-routers/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update logical router with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"logical router with id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = logical_router_id\n    if id is None:\n        module.exit_json(changed=False, msg='No logical router exist with display name %s' % display_name)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(logical_router_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/logical-routers/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete logical router with id %s. Error[%s].\" % (id, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=id, message=\"logical router with id %s deleted.\" % id)\n\n\ndef checkRedundantUplinkPortIds(existingHaVipConfigs, newHaVipConfigs):\n    if len(existingHaVipConfigs) != len(newHaVipConfigs):\n        return False\n    for i in range(len(existingHaVipConfigs)):\n        firstVal = ordered(existingHaVipConfigs[i]['redundant_uplink_port_ids'])\n        secondVal = ordered(newHaVipConfigs[i]['redundant_uplink_port_ids'])\n        if firstVal != secondVal:\n            return False\n    return True\n\n\ndef compareTags(existing_logical_router, new_logical_router):\n    return ordered(existing_logical_router['tags']) == ordered(new_logical_router['tags'])\n\n\ndef ordered(obj):\n    if isinstance(obj, dict):\n        return sorted((k, ordered(v)) for k, v in obj.items())\n    if isinstance(obj, list):\n        return sorted(ordered(x) for x in obj)\n    else:\n        return obj\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_logical_routers_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_logical_routers_facts\nshort_description: List Logical Routers\ndescription: Returns information about all logical routers, including the UUID, internal\n              and external transit network addresses, and the router type (TIER0 or\n              TIER1). You can get information for only TIER0 routers or only the TIER1\n              routers by including the router_type query parameter.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: List Logical Routers\n  nsxt_logical_routers_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/logical-routers', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing list of logical routers. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_logical_switches.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_logical_switches\nshort_description: Create a Logical Switch\ndescription: Creates a new logical switch. The request must include the\n             transport_zone_id, display_name, and admin_state (UP or DOWN). The\n             replication_mode (MTEP or SOURCE) is required for overlay logical\n             switches, but not for VLAN-based logical switches. A vlan needs to be\n             provided for VLAN-based logical switches\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n    address_bindings:\n        description: Address bindings for the Logical switch\n        required: false\n        type: array of PacketAddressClassifier\n    admin_state:\n        description: Represents Desired state of the Logical Switch\n        required: true\n        type: str\n    display_name:\n        description: Display name\n        required: true\n        type: str\n    extra_configs:\n        description: 'This property could be used for vendor specific configuration in key \n                      value string pairs, the setting in extra_configs will be automatically\n                      inheritted by logical ports in the logical switch.'\n        required: false\n        type: array of ExtraConfig\n    hybrid:\n        description: 'If this flag is set to true, then all the logical switch ports attached\n                      to this logical switch will behave in a hybrid fashion. The hybrid \n                      logical switch port indicates to NSX that the VM intends to operate in \n                      underlay mode, but retains the ability to forward egress traffic to the\n                      NSX overlay network.\n                  \n                      This flag can be enabled only for the logical switches in the overlay \n                      type transport zone which has host switch mode as STANDARD and also has \n                      either CrossCloud or CloudScope tag scopes.\n                  \n                      Only the NSX public cloud gateway (PCG) uses this flag, other host agents \n                      like ESX, KVM and Edge will ignore it. This property cannot be modified \n                      once the logical switch is created.'\n        required: false\n        type: boolean\n    ip_pool_name:\n        description: IP pool name\n        required: false\n        type: str\n    lswitch_id:\n        description: LSwitch ID\n        required: false\n        type: str\n    mac_pool_id:\n        description: Mac pool id that associated with a LogicalSwitch.\n        required: false\n        type: str\n    mac_pool_name:\n        description: Mac pool name that associated with a LogicalSwitch.\n        required: false\n        type: str\n    replication_mode:\n        description: Replication mode of the Logical Switch\n        required: false\n        type: str\n    description:\n        description: Description of the resource\n        required: False\n        type: str\n    span:\n        description: List of Local Manager IDs the logical switch extends\n        required: False\n        type: list\n    tags:\n        description: Opaque identifiers meaningful to the API user\n        required: False\n        type: list\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'. \n                    'present' is used to create or update resource. \n                    'absent' is used to delete resource.\"\n        required: true\n    switch_type:\n        description: 'This readonly field indicates purpose of a LogicalSwitch. It is set\n                      by manager internally and any user provided values will not be honored.\n                      DEFAULT type LogicalSwitches are created for basic L2 connectivity by API\n                      users.\n                      SERVICE_PLANE type LogicalSwitches are system created service plane \n                      LogicalSwitches\n                      Service Insertion service.'\n        required: false\n        type: str\n    switching_profiles:\n        description: List of Switching Profile Names and type\n        required: false\n        type: list\n    transport_zone_name:\n        description: Transport Zone Name\n        required: true\n        type: str\n    uplink_teaming_policy_name:\n        description: This name has to be one of the switching uplink teaming policy names\n                     listed inside the logical switch's TransportZone. If this field is not \n                     specified, the logical switch will not have a teaming policy associated \n                     with it and the host switch's default teaming policy will be used.\n        required: false\n        type: str\n    vlan:\n        description: 'This property is dedicated to VLAN based network, to set VLAN of logical\n                      network. It is mutually exclusive with ''vlan_trunk_spec''.'\n        required: false\n        type: int\n    vlan_trunk_spec:\n        description: 'This property is used for VLAN trunk specification of logical switch.\n                      It''s mutually exclusive with ''vlan''. Also it could be set to do guest \n                      VLAN tagging in overlay network.'\n        required: false\n        type: dict\n        vlan_ranges:\n            description: Trunk VLAN id ranges\n            required: true\n            type: array of TrunkVlanRange\n    vni:\n        description: 'Only for OVERLAY network. A VNI will be auto-allocated from the\n                      default VNI pool if not given; otherwise the given VNI has to be\n                      inside the default pool and not used by any other LogicalSwitch.'\n        required: false\n        type: int\n    \n'''\n\nEXAMPLES = '''\n- name: Create logical switch\n  nsxt_logical_switches:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    display_name: \"test_lswitch\"\n    replication_mode: \"SOURCE\"\n    admin_state: \"UP\"\n    transport_zone_name: \"TZ1\"\n    state: \"present\"\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request, validate_nsx_mp_support\nfrom ansible.module_utils._text import to_native\n\ndef get_logical_switch_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs', 'lswitch_id']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_logical_switches(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/logical-switches', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing logical switches. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_lswitch_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    logical_switchs = get_logical_switches(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for logical_switch in logical_switchs['results']:\n        if logical_switch.__contains__('display_name') and logical_switch['display_name'] == display_name:\n            return logical_switch\n    return None\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['id']\n    module.fail_json(msg='No id existe with display name %s' % display_name)\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, logical_switch_params ):\n    if 'ip_pool_name' in logical_switch_params:\n        logical_switch_params['ip_pool_id'] = get_id_from_display_name (module, manager_url,\n                                                                mgr_username, mgr_password, validate_certs,\n                                                                \"/pools/ip-pools\", logical_switch_params.pop('ip_pool_name', None))\n    if 'mac_pool_name' in logical_switch_params and 'mac_pool_id' not in logical_switch_params:\n        logical_switch_params['mac_pool_id'] = get_id_from_display_name (module, manager_url,\n                                                                mgr_username, mgr_password, validate_certs,\n                                                                \"/pools/mac-pools\", logical_switch_params.pop('mac_pool_name', None))\n    if 'mac_pool_name' in logical_switch_params and 'mac_pool_id' in logical_switch_params:\n        logical_switch_params.pop('mac_pool_name', None)\n    logical_switch_params['transport_zone_id'] = get_id_from_display_name (module, manager_url,\n                                                                mgr_username, mgr_password, validate_certs,\n                                                                \"/transport-zones\", logical_switch_params.pop('transport_zone_name', None))\n    switch_profiles = logical_switch_params.pop('switching_profiles', None)\n\n    switch_profile_ids = []\n    for switch_profile in switch_profiles or []:\n        profile_obj = {}\n        profile_obj['value'] = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                                \"/switching-profiles\", switch_profile['name'])\n        profile_obj['key'] = switch_profile['type']\n        switch_profile_ids.append(profile_obj)\n    logical_switch_params['switching_profile_ids'] = switch_profile_ids\n    return logical_switch_params\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, logical_switch_with_ids):\n    existing_logical_switch = get_lswitch_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, logical_switch_with_ids['display_name'])\n    if existing_logical_switch is None:\n        return False\n    if existing_logical_switch.__contains__('vlan') and logical_switch_with_ids.__contains__('vlan') and \\\n        existing_logical_switch['vlan'] != logical_switch_with_ids['vlan']:\n        return True\n\n    if logical_switch_with_ids.__contains__('vlan_trunk_spec') and existing_logical_switch.__contains__('vlan_trunk_spec') and \\\n        existing_logical_switch['vlan_trunk_spec']['vlan_ranges'] != logical_switch_with_ids['vlan_trunk_spec']['vlan_ranges']:\n        return True\n    if existing_logical_switch.__contains__('switching_profile_ids') and logical_switch_with_ids.__contains__('switching_profile_ids') and \\\n        existing_logical_switch['switching_profile_ids'] != logical_switch_with_ids['switching_profile_ids']:\n        return True\n    if existing_logical_switch['admin_state'] != logical_switch_with_ids['admin_state']:\n        return True\n    if existing_logical_switch.__contains__('replication_mode') and logical_switch_with_ids.__contains__('replication_mode') and \\\n        existing_logical_switch['replication_mode'] != logical_switch_with_ids['replication_mode']:\n        return True\n    if existing_logical_switch.__contains__('hybrid') and logical_switch_with_ids.__contains__('hybrid') and \\\n        existing_logical_switch['hybrid'] != logical_switch_with_ids['hybrid']:\n        return True\n    return False\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                        switch_type=dict(required=False, type='str'),\n                        replication_mode=dict(required=False, type='str'),\n                        extra_configs=dict(required=False, type='list'),\n                        uplink_teaming_policy_name=dict(required=False, type='str'),\n                        transport_zone_name=dict(required=True, type='str'),\n                        ip_pool_name=dict(required=False, type='str'),\n                        vlan=dict(required=False, type='int'),\n                        hybrid=dict(required=False, type='bool'),\n                        mac_pool_id=dict(required=False, type='str'),\n                        mac_pool_name=dict(required=False, type='str'),\n                        vni=dict(required=False, type='int'),\n                        vlan_trunk_spec=dict(required=False, type='dict',\n                        vlan_ranges=dict(required=True, type='list')),\n                        admin_state=dict(required=True, type='str'),\n                        address_bindings=dict(required=False, type='list'),\n                        switching_profiles=dict(required=False, type='list'),\n                        lswitch_id=dict(required=False, type='str'),\n                        description=dict(required=False, type='str'),\n                        span=dict(required=False, type='list'),\n                        tags=dict(required=False, type='list'),\n                        state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  logical_switch_params = get_logical_switch_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  validate_nsx_mp_support(module, manager_url, mgr_username, mgr_password, validate_certs)\n\n  changed = True\n  lswitch_dict = get_lswitch_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  lswitch_id, revision = None, None\n  if lswitch_dict:\n    lswitch_id = lswitch_dict['id']\n    revision = lswitch_dict['_revision']\n\n  if state == 'present':\n    body = update_params_with_id(module, manager_url, mgr_username, mgr_password, validate_certs, logical_switch_params)\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, body)\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n\n    if lswitch_id is None:\n      # add the logical_switch\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(body)), id=lswitch_id)\n      request_data = json.dumps(body)\n      try:\n          if lswitch_id:\n              module.exit_json(changed=False, id=lswitch_id, message=\"Logical switch with display_name %s already exist.\"% module.params['display_name'])\n\n          (rc, resp) = request(manager_url+ '/logical-switches', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to add logical switch. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"Logical switch with display name %s created.\" % module.params['display_name'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(body)), id=lswitch_id)\n\n      body['_revision'] = revision # update current revision\n      request_data = json.dumps(body)\n      id = lswitch_id\n      try:\n          (rc, resp) = request(manager_url+ '/logical-switches/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update logical switch with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"logical switch with lswitch id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = lswitch_id\n    if id is None:\n        module.exit_json(changed=False, msg='No logical switch exist with display name %s' % display_name)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(logical_switch_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/logical-switches/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete logical switch with id %s. Error[%s].\" % (id, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=id, message=\"Logical switch with zone id %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_logical_switches_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_logical_switches_facts\nshort_description: List All Logical Switches\ndescription: Returns information about all configured logical switches.\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: List All Logical Switches\n  nsxt_logical_switches_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/logical-switches', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing list of logical ports. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_manager_auto_deployment.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_manager_auto_deployment\nshort_description: 'Deploy and register a cluster node VM'\ndescription: \"Deploys a cluster node VM as specified by the deployment config.\n              Once the VM is deployed and powered on, it will automatically join the\n              existing cluster.\"\nversion_added: '2.7'\nauthor: 'Rahul Raghuvanshi'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    deployment_requests:\n        description: 'Cluster node VM deployment requests to be deployed by the Manager.'\n        required: true\n        type: 'array of ClusterNodeVMDeploymentRequest'\n    node_id:\n        description: 'Unique node-id of a principal'\n        required: false\n        type: str\n    node_name:\n        description: 'Unique node-name of a principal'\n        required: false\n        type: str\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n    \n'''\n\nEXAMPLES = '''\n  - name: Deploy and register a cluster node VM\n    nsxt_manager_auto_deployment:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      deployment_requests:\n      - roles:\n      - MANAGER\n      - CONTROLLER\n        form_factor: \"MEDIUM\"\n        user_settings:\n          cli_password: \"Admin!23Admin\"\n          root_password: \"Admin!23Admin\"\n        deployment_config:\n          placement_type: VsphereClusterNodeVMDeploymentConfig\n          vc_id: \"7503e86e-c502-46fc-8d91-45a06d314d88\"\n          management_network: \"network-44\"\n          ignore_ssl_verification: True\n          disk_provisioning: \"LAZY_ZEROED_THICK\"\n          hostname: \"manager-2\"\n          compute: \"domain-c49\"\n          storage: \"datastore-43\"\n          default_gateway_addresses:\n          - 10.112.203.253\n          management_port_subnets:\n          - ip_addresses:\n            - 10.112.201.25\n            prefix_length: \"19\"\n           management_port_ipv6_subnets:\n                - ip_addresses:\n                    - 2620:124:6020:1045::1c\n                  prefix_length: \"64\"\n              default_ipv6_gateway_addresses:\n                - 2620:124:6020:1045::253\n      state: present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request, get_vc_ip_from_display_name\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vcenter_utils import get_resource_id_from_name\nfrom ansible.module_utils._text import to_native\n\nFAILED_STATES = [\"UNKNOWN_STATE\", \"VM_DEPLOYMENT_FAILED\", \"VM_POWER_ON_FAILED\", \"VM_ONLINE_FAILED\", \"VM_CLUSTERING_FAILED\",\n                      \"VM_DECLUSTER_FAILED\", \"VM_POWER_OFF_FAILED\", \"VM_UNDEPLOY_FAILED\"]\nIN_PROGRESS_STATES = [\"VM_DEPLOYMENT_QUEUED\", \"VM_DEPLOYMENT_IN_PROGRESS\", \"VM_POWER_ON_IN_PROGRESS\",  \"WAITING_TO_REGISTER_VM\", \"VM_WAITING_TO_CLUSTER\",\n                      \"VM_WAITING_TO_COME_ONLINE\", \"VM_CLUSTERING_IN_PROGRESS\", \"WAITING_TO_UNDEPLOY_VM\", \"VM_DECLUSTER_IN_PROGRESS\",\n                      \"VM_POWER_OFF_IN_PROGRESS\", \"VM_UNDEPLOY_IN_PROGRESS\", \"VM_UNDEPLOY_SUCCESSFUL\"]\nSUCCESS_STATES = [\"VM_CLUSTERING_SUCCESSFUL\", \"VM_DECLUSTER_SUCCESSFUL\"]\ndef get_node_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs', 'node_id']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_nodes(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/cluster/nodes/deployments', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing controller-manager node. Error [%s]' % (to_native(err)))\n    return resp\n\ndef check_node_exist(existing_nodes_data, module):\n    new_deployment_requests = module.params['deployment_requests']\n    for result in existing_nodes_data['results']:\n        for new_deployment_request in new_deployment_requests:\n            if result['deployment_config']['hostname'] == new_deployment_request['deployment_config']['hostname']:\n                return True, result['deployment_config']['hostname']\n    return False, None\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name, exit_if_not_found=True):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['id']\n    if exit_if_not_found:\n        module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, node_params ):\n    for deployment_request in node_params['deployment_requests']:\n        vc_name = deployment_request['deployment_config'].pop('vc_name', None)\n        deployment_request['deployment_config']['vc_id'] = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                    \"/fabric/compute-managers\", vc_name)\n    return node_params\n\ndef wait_till_create(vm_id, module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      while True:\n          (rc, resp) = request(manager_url+ '/cluster/nodes/deployments/%s/status'% vm_id, headers=dict(Accept='application/json'),\n                        url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n          if any(resp['status'] in progress_status for progress_status in IN_PROGRESS_STATES):\n              time.sleep(10)\n          elif any(resp['status'] in progress_status for progress_status in SUCCESS_STATES):\n              time.sleep(5)\n              return\n          else:\n              module.fail_json(msg= 'Error in controller-manager node deployment: %s'%(str(resp['status'])))\n    except Exception as err:\n      module.fail_json(msg='Error accessing controller-manager node status. Error [%s]' % (to_native(err)))\n\ndef wait_till_delete(vm_id, module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      count = 0;\n      #Wait for maximum 10 minute for vm deletion\n      while True and count < 20:\n          (rc, resp) = request(manager_url+ '/cluster/nodes/deployments/%s/status'% vm_id, headers=dict(Accept='application/json'),\n                        url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n          if (resp == {}):\n              time.sleep(10)\n              break\n          time.sleep(30)\n          count = count + 1\n    except Exception as err:\n      time.sleep(5)\n      return\n\ndef get_node_id_from_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name):\n    '''\n        Given Name of the auto deployed node, This function retrieves the node id. If not found it fails.\n    '''\n    try:\n        (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n        module.fail_json(msg='Error accessing vm id for host name %s. Error [%s]' % (display_name, to_native(err)))\n    for result in resp['results']:\n        if result.__contains__('deployment_config') and result['deployment_config'].__contains__('hostname') and \\\n        result['deployment_config']['hostname'] == display_name:\n            if result.__contains__('vm_id'):\n              return result['vm_id']\n    module.fail_json(msg='No auto deployed node exist with display name %s' % display_name)\n\n\ndef inject_vcenter_info(module, manager_url, mgr_username, mgr_password, validate_certs, node_params):\n  '''\n  params:\n  - transport_node_params: These are the transport node parameters passed from playbook file\n  result:\n  - takes the vecenter parameters accepted by playbook and converts it into the form accepted\n    by cluster node deployment api using pyvmomi functions.\n  '''\n  for deployment_request in node_params['deployment_requests']:\n    deployment_config = deployment_request['deployment_config']\n    if deployment_config.__contains__('ignore_ssl_verification'):\n        ignore_ssl_verification = deployment_config['ignore_ssl_verification']\n    else:\n        ignore_ssl_verification = True\n    if deployment_config.__contains__('vc_username') and deployment_config.__contains__('vc_password'):\n      vc_name = deployment_config['vc_name']\n      vc_ip = get_vc_ip_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                         \"/fabric/compute-managers\", vc_name)\n\n\n      vc_username = deployment_config.pop('vc_username', None)\n\n      vc_password = deployment_config.pop('vc_password', None)\n\n      if deployment_config.__contains__('host'):\n        host = deployment_config.pop('host', None)\n        host_id = get_resource_id_from_name(module, vc_ip, vc_username, vc_password,\n                                      'host', host, ignore_ssl_verification)\n        deployment_request['deployment_config']['host_id'] = str(host_id)\n\n      storage = deployment_config.pop('storage')\n      storage_id = get_resource_id_from_name(module, vc_ip, vc_username, vc_password,\n                                           'storage', storage, ignore_ssl_verification)\n\n      deployment_request['deployment_config']['storage_id'] = str(storage_id)\n\n      cluster = deployment_config.pop('compute')\n      cluster_id = get_resource_id_from_name(module, vc_ip, vc_username, vc_password,\n                                           'cluster', cluster, ignore_ssl_verification)\n\n      deployment_request['deployment_config']['compute_id'] = str(cluster_id)\n\n      management_network = deployment_config.pop('management_network')\n      management_network_id = get_resource_id_from_name(module, vc_ip, vc_username, vc_password,\n                                               'network', management_network, ignore_ssl_verification)\n\n      deployment_request['deployment_config']['management_network_id'] = str(management_network_id)\n\n      if deployment_config.__contains__('host'):\n        deployment_request['deployment_config'].pop('host', None)\n      deployment_request['deployment_config'].pop('cluster', None)\n      deployment_request['deployment_config'].pop('storage', None)\n      deployment_request['deployment_config'].pop('management_network', None)\n      deployment_request['deployment_config'].pop('ignore_ssl_verification', None)\n\n    else:\n      if deployment_config.__contains__('host'):\n        host_id = deployment_request['deployment_config'].pop('host', None)\n        deployment_request['deployment_config']['host_id'] = host_id\n \n      cluster_id = deployment_request['deployment_config'].pop('compute', None)\n      storage_id = deployment_request['deployment_config'].pop('storage', None)\n      management_network_id = deployment_request['deployment_config'].pop('management_network', None)\n      deployment_request['deployment_config'].pop('ignore_ssl_verification', None)\n \n      deployment_request['deployment_config']['compute_id'] = cluster_id\n      deployment_request['deployment_config']['storage_id'] = storage_id\n      deployment_request['deployment_config']['management_network_id'] = management_network_id\n\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(deployment_requests=dict(required=True, type='list'),\n                    node_name=dict(required=False, type='str'),\n                    node_id=dict(required=False, type='str'),\n                    state=dict(required=True, choices=['present', 'absent']))\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  node_params = get_node_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n  inject_vcenter_info(module, manager_url, mgr_username, mgr_password, validate_certs, node_params)\n  update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, node_params)\n\n  request_data = json.dumps(node_params)\n  results = get_nodes(module, manager_url, mgr_username, mgr_password, validate_certs)\n  is_node_exist, hostname = check_node_exist(results, module)\n  if state == 'present':\n    # add Manager Controller node\n    if is_node_exist:\n      module.exit_json(changed=False, message=\"Controller-manager node with hostname %s already exist.\"% hostname)\n    if module.check_mode:\n      module.exit_json(changed=True, debug_out=str(request_data))\n    try:\n      (rc, resp) = request(manager_url+ '/cluster/nodes/deployments', data=request_data, headers=headers, method='POST',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg=\"Failed to add controller-manager node. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n    for node in resp['results']:\n      wait_till_create(node['vm_id'], module, manager_url, mgr_username, mgr_password, validate_certs)\n    time.sleep(5)\n    module.exit_json(changed=True, body= str(resp), message=\"Controller-manager node deployed.\")\n\n  elif state == 'absent':\n    id = None\n    if module.params['node_id']:\n      id = module.params['node_id']\n    elif module.params['node_name']:\n      node_name = module.params['node_name']\n    else:\n      module.fail_json(msg=\"Failed to delete manager node as non of node_id, node_name is provided.\")\n    if not id:\n      id = get_node_id_from_name(module, manager_url, mgr_username, mgr_password, validate_certs, '/cluster/nodes/deployments', node_name)\n    if is_node_exist:\n      # delete node\n      if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(request_data))\n      try:\n        (rc, resp) = request(manager_url+ '/cluster/nodes/deployments/%s?action=delete' % id, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n        module.fail_json(msg=\"Failed to delete controller-manager node with id %s. Error[%s].\" % (id, to_native(err)))\n    else:\n      module.fail_json(msg=\"Controller-manager node with id %s does not exist.\" % id)\n\n    wait_till_delete(id, module, manager_url, mgr_username, mgr_password, validate_certs)\n    time.sleep(5)\n    module.exit_json(changed=True, id=id, message=\"Controller-manager node with node id %s deleted.\" % id)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_manager_auto_deployment_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\nmodule: nsxt_manager_auto_deployment_facts\nshort_description: 'Returns info for all cluster node VM auto-deployment attempts'\ndescription: 'Returns request information for every attempted deployment of a \n              cluster node VM'\nversion_added: '2.7'\nauthor: 'Rahul Raghuvanshi'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- nsxt_manager_auto_deployment_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/cluster/nodes/deployments', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing controllers. Error [%s]' % (to_native(err)))\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_manager_status.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_manager_status\nshort_description: Shows status of nsxt manager\ndescription: Shows status of nsxt manager\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: Shows status of nsxt manager\n  nsxt_manager_status:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      wait_time: 50\n'''\n\nRETURN = '''# '''\nimport json, time\nfrom datetime import datetime\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(wait_time=dict(required=False, type='int'))\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  wait_time = 10 # wait till 30 min\n  while wait_time < (module.params['wait_time'] *60):\n      try:\n        current_time = datetime.now()\n        (rc, resp) = request(manager_url+ '/cluster-manager/status', headers=dict(Accept='application/json'),\n                        url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n        if \"overall_status\" in resp and resp[\"overall_status\"] == \"STABLE\":\n            module.exit_json(changed=changed, msg= \" NSX manager is UP\")\n        else:\n            time_diff = datetime.now() - current_time\n            time.sleep(10)\n            wait_time = time_diff.seconds + wait_time + 10\n      except Exception as err:\n        time_diff = datetime.now() - current_time\n        time.sleep(10)\n        wait_time = time_diff.seconds + wait_time + 10\n  module.fail_json(changed=changed, msg= \" Error accessing nsx manager. Timed out\")\n\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_bfd_profile.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_policy_bfd_profile\nshort_description: Create or Delete a Policy BFD Profile\ndescription:\n    Creates or deletes a Policy BFD Profile.\n    Required attributes include id and display_name.\nversion_added: \"2.8\"\nauthor: Gautam Verma\nextends_documentation_fragment:\n    - vmware.ansible_for_nsxt.vmware_nsxt\noptions:\n    id:\n        description: The id of the BFD Profile.\n        required: true\n        type: str\n    description:\n        description: BFD Profile description.\n        type: str\n    interval:\n        description:\n            - Time interval between heartbeat packets in milliseconds\n            - Should be in the range [50-60000]\n        type: int\n        default: 500\n    multiple:\n        description:\n            - Declare dead multiple.\n            - Number of times heartbeat packet is missed before BFD declares\n              the neighbor is down.\n            - Should be in the range [2-16]\n        type: int\n        default: 3\n'''\n\nEXAMPLES = '''\n- name: Update BFD Profile\n  nsxt_policy_bfd_profile:\n    hostname: \"10.10.10.10\"\n    nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n    nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n    validate_certs: False\n    display_name: test-bfd-profile\n    state: present\n    interval: 200\n    multiple: 10\n'''\n\nRETURN = '''# '''\n\nimport json\nimport time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_base_resource import NSXTBaseRealizableResource\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import BFD_PROFILE_URL\nfrom ansible.module_utils._text import to_native\n\n\nclass NSXTBFDProfile(NSXTBaseRealizableResource):\n    @staticmethod\n    def get_resource_spec():\n        bfd_profile_arg_spec = {}\n        bfd_profile_arg_spec.update(\n            interval=dict(\n                default=500,\n                type='int'\n            ),\n            multiple=dict(\n                default=3,\n                type='int'\n            )\n        )\n        return bfd_profile_arg_spec\n\n    @staticmethod\n    def get_resource_base_url(baseline_args=None):\n        return BFD_PROFILE_URL\n\n\nif __name__ == '__main__':\n    bfd_profile = NSXTBFDProfile()\n    bfd_profile.realize()\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_gateway_policy.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_policy_gateway_policy\nshort_description: Update a Gateway Policy\ndescription:\n    Updates a Gateway Policy\n    Required attributes include id or display_name\nversion_added: \"2.8\"\nauthor: Gautam Verma\nextends_documentation_fragment:\n    - vmware.ansible_for_nsxt.vmware_nsxt\noptions:\n    id:\n        description: The id of the Gateway Policy\n        required: false\n        type: str\n    description:\n        description: Gateway Policy description.\n        type: str\n    category:\n        description:\n            Policy Framework for Edge Firewall provides six pre-defined\n            categories - \"Emergency\", \"SystemRules\", \"SharedPreRules\",\n            \"LocalGatewayRules\", \"AutoServiceRules\" and \"Default\", in order\n            of priority of rules. All categories are allowed for Gatetway\n            Policies that belong to 'default' Domain. However, for user\n            created domains, category is restricted to \"SharedPreRules\" or\n            \"LocalGatewayRules\" only. Also, the users can add/modify/delete\n            rules from only the \"SharedPreRules\" and \"LocalGatewayRules\"\n            categories. If user doesn't specify the category then defaulted\n            to \"Rules\". System generated category is used by NSX created\n            rules, for example BFD rules. Autoplumbed category used by NSX\n            verticals to autoplumb data path rules. Finally, \"Default\"\n            category is the placeholder default rules with lowest in the order\n            of priority\n        required: false\n        type: str\n        choices:\n            - Emergency\n            - SystemRules\n            - SharedPreRules\n            - LocalGatewayRules\n            - AutoServiceRules\n            - Default\n        default: Default\n    comments:\n        description: Comments for security policy lock/unlock\n        required: false\n        type: str\n    locked:\n        description: Indicates whether a security policy should be locked.\n                     If the security policy is locked by a user, then no other\n                     user would be able to modify this security policy. Once\n                     the user releases the lock, other users can update this\n                     security policy\n        required: false\n        type: bool\n        default: false\n    rules:\n        description: Rules that are a part of this GatewayPolicy\n        type: list\n        suboptions:\n            action:\n                description: The action to be applied to all the\n                             services\n                type: str\n                choices:\n                    - \"ALLOW\"\n                    - \"DROP\"\n                    - \"REJECT\"\n            description:\n                description: Description of this resource\n                type: str\n            destination_groups:\n                description: Destination group paths\n                type: list\n                required: true\n            destinations_excluded:\n                description: Negation of destination groups\n\n                             If set to true, the rule gets applied on\n                             all the groups that are NOT part of the\n                             destination groups. If false, the rule\n                             applies to the destination groups.\n                type: bool\n                default: false\n            direction:\n                description: Define direction of traffic.\n                type: str\n                choices:\n                    - IN\n                    - OUT\n                    - IN_OUT\n            disabled:\n                description: Flag to disable the rule\n                type: bool\n                default: false\n            display_name:\n                description: Identifier to use when displaying entity\n                             in logs or GUI.\n\n                             Defaults to ID if not set\n                type: str\n            id:\n                description: Unique identifier of this resource\n                type: str\n                required: true\n            ip_protocol:\n                description:\n                    - IPv4 vs IPv6 packet type\n                    - Type of IP packet that should be matched while enforcing\n                      the rule. The value is set to IPV4_IPV6 for Layer3 rule\n                      if not specified. For Layer2/Ether rule the value must be\n                      null.\n                type: str\n                choices:\n                    - IPV4\n                    - IPV6\n                    - IPV4_IPV6\n            logged:\n                description: Flag to enable packet logging.\n                             Default is disabled.\n                type: bool\n                default: false\n            notes:\n                description: Text for additional notes on changes\n                type: str\n            profiles:\n                description:\n                    - Layer 7 service profiles\n                    - Holds the list of layer 7 service profile paths. These\n                      profiles accept attributes and sub-attributes of various\n                      network services (e.g. L4 AppId, encryption algorithm,\n                      domain name, etc) as key value pairs\n                type: list\n            scope:\n                description: The list of policy paths where the rule is applied\n                             LR/Edge/T0/T1/LRP etc. Note that a given rule can\n                             be applied on multiple LRs/LRPs\n                type: list\n            sequence_number:\n                description: Sequence number of the this Rule\n                type: int\n            service_entries:\n                description:\n                    - Raw services\n                    - In order to specify raw services this can be used,\n                      along with services which contains path to services.\n                      This can be empty or null\n                type: list\n                elements: dict\n            services:\n                description: Paths of services\n                             In order to specify all services, use the\n                             constant \"ANY\". This is case insensitive.\n                             If \"ANY\" is used, it should be the ONLY\n                             element in the services array. Error will\n                             be thrown if ANY is used in conjunction\n                             with other values.\n                type: list\n                required: true\n            source_groups:\n                description: Source group paths\n                type: list\n                required: true\n            sources_excluded:\n                description: Negation of source groups\n\n                             If set to true, the rule gets applied on\n                             all the groups that are NOT part of the\n                             source groups. If false, the rule applies\n                             to the source groups\n                type: bool\n                default: false\n            tag:\n                description:\n                    - Tag applied on the rule\n                    - User level field which will be printed in CLI and packet\n                      logs.\n                type: str\n            tags:\n                description: Opaque identifiers meaningful to the API user\n                type: list\n                elements: dict\n                suboptions:\n                    scope:\n                        description: Tag scope\n                        type: str\n                    tag:\n                        description: Tag value\n                        type: str\n    scheduler_path:\n        description:\n            - Path to the scheduler for time based scheduling\n            - Provides a mechanism to apply the rules in this policy for a\n              specified time duration\n        required: false\n        type: str\n    scope:\n        description: The list of group paths where the rules in this policy\n                     will get applied. This scope will take precedence over\n                     rule level scope. Supported only for security and\n                     redirection policies. In case of RedirectionPolicy, it is\n                     expected only when the policy is NS and redirecting to\n                     service chain.\n        required: false\n        type: list\n        element: str\n    sequence_number:\n        description:\n            - Sequence number to resolve conflicts across Domains\n            - This field is used to resolve conflicts between security\n              policies across domains. In order to change the sequence number\n              of a policy one can fire a POST request on the policy entity\n              with a query parameter action=revise The sequence number field\n              will reflect the value of the computed sequence number upon\n              execution of the above mentioned POST request. For scenarios\n              where the administrator is using a template to update several\n              security policies, the only way to set the sequence number is\n              to explicitly specify the sequence number for each security\n              policy. If no sequence number is specified in the payload, a\n              value of 0 is assigned by default. If there are multiple\n              policies with the same sequence number then their order is not\n              deterministic. If a specific order of policies is desired, then\n              one has to specify unique sequence numbers or use the POST\n              request on the policy entity with a query parameter\n              action=revise to let the framework assign a sequence number\n        required: false\n        type: int\n    stateful:\n        description:\n            - Stateful nature of the entries within this security policy.\n            - Stateful or Stateless nature of security policy is enforced on\n              all rules in this security policy. When it is stateful, the state\n              of the network connects are tracked and a stateful packet\n              inspection is performed. Layer3 security policies can be stateful\n              or stateless. By default, they are stateful. Layer2 security\n              policies can only be stateless.\n        required: false\n        type: bool\n    tcp_strict:\n        description:\n            - Enforce strict tcp handshake before allowing data packets\n            - Ensures that a 3 way TCP handshake is done before the data\n              packets are sent. tcp_strict=true is supported only for stateful\n              security policies.\n        required: false\n        type: bool\n'''\n\nEXAMPLES = '''\n- name: Update Gateway Policy\n  nsxt_policy_gateway_policy:\n    hostname: \"10.10.10.10\"\n    nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n    nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n    validate_certs: False\n    display_name: test-gateway-policy\n    state: present\n'''\n\nRETURN = '''# '''\n\nimport json\nimport time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_base_resource import NSXTBaseRealizableResource\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import GATEWAY_POLICY_URL\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.policy_resource_specs.security_policy import SPEC as SecurityPolicySpec\nfrom ansible.module_utils._text import to_native\n\n\nclass NSXTGatewayPolicy(NSXTBaseRealizableResource):\n    @staticmethod\n    def get_resource_spec():\n        gateway_policy_arg_spec = {}\n        gateway_policy_arg_spec.update(\n            SecurityPolicySpec\n        )\n        gateway_policy_arg_spec.pop('connectivity_strategy')\n        return gateway_policy_arg_spec\n\n    @staticmethod\n    def get_resource_base_url(baseline_args):\n        return GATEWAY_POLICY_URL.format(\n            baseline_args[\"domain_id\"])\n\n    def update_resource_params(self, nsx_resource_params):\n        nsx_resource_params.pop('domain_id')\n\n\nif __name__ == '__main__':\n    gw_policy = NSXTGatewayPolicy()\n    gw_policy.realize(baseline_arg_names=[\"domain_id\"])\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_group.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_policy_group\nshort_description: Create or Delete a Policy Policy Group\ndescription:\n    Creates or deletes a Policy Policy Group.\n    Required attributes include id and display_name.\nversion_added: \"2.8\"\nauthor: Gautam Verma\nextends_documentation_fragment:\n    - vmware.ansible_for_nsxt.vmware_nsxt\noptions:\n    id:\n        description: The id of the Policy Policy Group.\n        required: false\n        type: str\n    description:\n        description: Policy Group description.\n        type: str\n    domain_id:\n        description: Domain ID.\n        type: str\n    expression:\n        description:\n            - The expression list must follow below criteria\n                - 1. A non-empty expression list, must be of odd size.\n                  In a list, with indices starting from 0, all\n                  non-conjunction expressions must be at\n                  even indices, separated by a conjunction expression\n                  at odd indices.\n                - 2. The total of ConditionExpression and\n                  NestedExpression in a list should not exceed 5.\n                - 3. The total of IPAddressExpression,\n                  MACAddressExpression, external IDs in an\n                  ExternalIDExpression and paths in a PathExpression\n                  must not exceed 500.\n                - 4. Each expression must be a valid Expression. See\n                  the definition of the Expression type for more\n                  information.\n        type: list\n    extended_expression:\n        description:\n            - Extended Expression allows additional higher level context to be\n              specified for grouping criteria (e.g. user AD group). This field\n              allow users to specified user context as the source of a firewall\n              rule for IDFW feature.  Current version only support a single\n              IdentityGroupExpression. In the future, this might expand to\n              support other conjunction and non-conjunction expression.\n            - The extended expression list must follow below criteria\n                - 1. Contains a single IdentityGroupExpression. No conjunction\n                  expression is supported\n                - 2. No other non-conjunction expression is supported, except\n                  for IdentityGroupExpression\n                - 3. Each expression must be a valid Expression. See the\n                  definition of the Expression type for more information\n                - 4. Extended expression are implicitly AND with expression\n                - 5. No nesting can be supported if this value is used\n                - 6. If a Group is using extended expression, this group must\n                  be the only member in the source field of an communication\n                  map\n        type: list\n    group_state:\n        description: Realization state of this group\n        type: str\n        choices:\n            - IN_PROGRESS\n            - SUCCESS\n            - FAILURE\n'''\n\nEXAMPLES = '''\n- name: create Policy Group\n  nsxt_policy_group:\n    hostname: \"10.10.10.10\"\n    nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n    nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n    validate_certs: False\n    id: test-lb-service\n    display_name: test-lb-service\n    state: \"present\"\n    domain_id: \"default\"\n    expression:\n      - member_type: \"VirtualMachine\"\n        value: \"webvm\"\n        key: \"Tag\"\n        operator: \"EQUALS\"\n        resource_type: \"Condition\"\n'''\n\nRETURN = '''# '''\n\nimport json\nimport time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_base_resource import NSXTBaseRealizableResource\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import POLICY_GROUP_URL\nfrom ansible.module_utils._text import to_native\n\n\nclass NSXTPolicyGroup(NSXTBaseRealizableResource):\n    @staticmethod\n    def get_resource_spec():\n        policy_group_arg_spec = {}\n        policy_group_arg_spec.update(\n            domain_id=dict(\n                required=True,\n                type='str'\n            ),\n            expression=dict(\n                required=True,\n                type='list'\n            ),\n            extended_expression=dict(\n                required=False,\n                type='list'\n            ),\n            group_state=dict(\n                required=False,\n                type='str'\n            ),\n        )\n        return policy_group_arg_spec\n\n    @staticmethod\n    def get_resource_base_url(baseline_args):\n        return POLICY_GROUP_URL.format(\n            baseline_args[\"domain_id\"]\n        )\n\n    def update_resource_params(self, nsx_resource_params):\n        nsx_resource_params.pop('domain_id')\n\n\nif __name__ == '__main__':\n    policy_group = NSXTPolicyGroup()\n    policy_group.realize(baseline_arg_names=[\"domain_id\"])\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_ip_block.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_policy_ip_block\nshort_description: Create or Delete a Policy IP Block\ndescription:\n    Creates or deletes a Policy IP Block.\n    Required attributes include id and display_name.\nversion_added: \"2.8\"\nauthor: Gautam Verma\nextends_documentation_fragment:\n    - vmware.ansible_for_nsxt.vmware_nsxt\noptions:\n    id:\n        description: The id of the Policy IP Block.\n        required: false\n        type: str\n    description:\n        description: IP Block description.\n        type: str\n    cidr:\n        description:\n            - A contiguous IP address space represented by network address\n              and prefix length\n            - Represents a network address and the prefix length which will\n              be associated with a layer-2 broadcast domain. Support only IPv4\n              CIDR.\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: create IP Block\n  nsxt_policy_ip_block:\n    hostname: \"10.10.10.10\"\n    nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n    nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n    validate_certs: False\n    id: test-ip-blk\n    display_name: test-ip-blk\n    state: \"present\"\n    cidr: \"192.168.0.0/16\"\n'''\n\nRETURN = '''# '''\n\nimport json\nimport time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_base_resource import NSXTBaseRealizableResource\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import IP_BLOCK_URL\nfrom ansible.module_utils._text import to_native\n\n\nclass NSXTIpBlock(NSXTBaseRealizableResource):\n    @staticmethod\n    def get_resource_spec():\n        ip_block_arg_spec = {}\n        ip_block_arg_spec.update(\n            cidr=dict(\n                required=True,\n                type='str'\n            )\n        )\n        return ip_block_arg_spec\n\n    @staticmethod\n    def get_resource_base_url(baseline_args=None):\n        return IP_BLOCK_URL\n\n\nif __name__ == '__main__':\n    ip_block = NSXTIpBlock()\n    ip_block.realize()\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_ip_block_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_ip_blocks_facts\nshort_description: Returns list of configured IP address blocks.\ndescription: Returns information about configured IP address blocks. Information includes\n             the id, display name, description & CIDR of IP address blocks\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: Lists all configured IP address blocks\n  nsxt_ip_block_facts:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n'''\n\nRETURN = '''# '''\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  manager_url = 'https://{}/policy/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(f\"{manager_url}/infra/ip-pools\", headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing list of ip blocks. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_ip_pool.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_policy_ip_pool\nshort_description: Create or Delete a Policy IP Pool\ndescription:\n    Creates or deletes a Policy IP Pool.\n    Required attributes include id and display_name.\nversion_added: \"2.8\"\nauthor: Gautam Verma\nextends_documentation_fragment:\n    - vmware.ansible_for_nsxt.vmware_nsxt\noptions:\n    id:\n        description: The id of the Policy IP Pool.\n        required: false\n        type: str\n    description:\n        description: Resource description.\n        type: str\n    pool_block_subnets:\n        type: list\n        element: dict\n        description: Specify the IP Pool Block Subnets that need to be created,\n                     updated, or deleted as a list of dict in this section\n        suboptions:\n            auto_assign_gateway:\n                description:\n                    - Indicate whether default gateway is to be reserved from\n                      the range\n                    - If this property is set to true, the first IP in the\n                      range will be reserved for gateway.\n                type: bool\n                default: true\n            description:\n                description: Resource description.\n                type: str\n            display_name:\n                description:\n                    - Display name.\n                    - If resource ID is not specified, display_name will be\n                      used as ID.\n                required: false\n                type: str\n            do_wait_till_create:\n                type: bool\n                default: false\n                description: Can be used to wait for the realization of\n                             subresource before the request to create the next\n                             resource is sent to the Manager\n            id:\n                description: The id of the Policy IP Pool Block Subnet.\n                required: false\n                type: str\n            ip_block_display_name:\n                description: Same as ip_block_id. Either one must be specified.\n                             If both are specified, ip_block_id takes\n                             precedence.\n                required: false\n                type: str\n            ip_block_id:\n                description: The ID of the IpAddressBlock from which the subnet\n                             is to be created\n                type: str\n            size:\n                description:\n                    - Represents the size or number of IP addresses in the\n                      subnet\n                    - The size parameter is required for subnet creation. It\n                      must be specified during creation but cannot be changed\n                      later.\n                type: int\n            state:\n                choices:\n                - present\n                - absent\n                description: \"State can be either 'present' or 'absent'.\n                            'present' is used to create or update resource.\n                            'absent' is used to delete resource.\"\n                required: true\n            tags:\n                description: Opaque identifiers meaningful to the API user.\n                type: dict\n                suboptions:\n                    scope:\n                        description: Tag scope.\n                        required: true\n                        type: str\n                    tag:\n                        description: Tag value.\n                        required: true\n                        type: str\n    pool_static_subnets:\n        type: list\n        element: dict\n        description: Specify the IP Pool Static Subnets that need to be\n                     created, updated, or deleted as a list of dict in\n                     this section\n        suboptions:\n            allocation_ranges:\n                description: A collection of IPv4 or IPv6 IP Pool Ranges.\n                type: list\n                element: dict\n                suboptions:\n                    start:\n                        description: The start IP Address of the IP Range.\n                        type: str\n                        required: true\n                    end:\n                        description: The end IP Address of the IP Range.\n                        type: str\n                        required: true\n            cidr:\n                description: Subnet representation is a network address\n                             and prefix length\n                type: str\n                required: true\n            description:\n                description: Resource description.\n                type: str\n            display_name:\n                description:\n                    - Display name.\n                    - If resource ID is not specified, display_name will be\n                      used as ID.\n                required: false\n                type: str\n            dns_nameservers:\n                description: The collection of upto 3 DNS servers\n                             for the subnet.\n                type: list\n                element: str\n            dns_suffix:\n                description: The DNS suffix for the DNS server.\n                type: str\n            do_wait_till_create:\n                type: bool\n                default: false\n                description: Can be used to wait for the realization of\n                             subresource before the request to create the next\n                             resource is sent to the Manager\n            gateway_ip:\n                description: The default gateway address on a\n                             layer-3 router.\n                type: str\n            id:\n                description: The id of the Policy IP Pool Block Subnet.\n                required: false\n                type: str\n            state:\n                choices:\n                - present\n                - absent\n                description: \"State can be either 'present' or 'absent'.\n                            'present' is used to create or update resource.\n                            'absent' is used to delete resource.\"\n            tags:\n                description: Opaque identifiers meaningful to the API user.\n                type: dict\n                suboptions:\n                    scope:\n                        description: Tag scope.\n                        required: true\n                        type: str\n                    tag:\n                        description: Tag value.\n                        required: true\n                        type: str\n'''\n\nEXAMPLES = '''\n- name: create IP Pool\n  nsxt_policy_ip_pool:\n    hostname: \"10.10.10.10\"\n    nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n    nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n    validate_certs: False\n    id: test-ip-pool\n    display_name: test-ip-pool\n    state: \"absent\"\n    tags:\n    - tag: \"a\"\n      scope: \"b\"\n    pool_block_subnets:\n      - id: test-ip-subnet-1\n        state: present\n        ip_block_id: \"test-ip-blk-1\"\n        size: 16\n      - display_name: test-ip-subnet-2\n        state: present\n        ip_block_id: \"test-ip-blk-1\"\n        size: 16\n      - display_name: test-ip-subnet-3\n        state: present\n        ip_block_id: \"test-ip-blk-1\"\n        size: 8\n    pool_static_subnets:\n      - id: test-ip-static-subnet-1\n        state: present\n        allocation_ranges:\n          - start: '192.116.0.10'\n            end: '192.116.0.20'\n          - start: '192.116.0.30'\n            end: '192.116.0.40'\n        cidr: '192.116.0.0/26'\n      - display_name: test-ip-static-subnet-2\n        state: present\n        allocation_ranges:\n          - start: '192.116.1.10'\n            end: '192.116.1.20'\n          - start: '192.116.1.30'\n            end: '192.116.1.40'\n        cidr: '192.116.1.0/26'\n'''\n\nRETURN = '''# '''\n\nimport json\nimport time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_base_resource import NSXTBaseRealizableResource\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import (\n    IP_ADDRESS_POOL_SUBNET_URL, IP_BLOCK_URL, IP_POOL_URL)\nfrom ansible.module_utils._text import to_native\n\n\nclass NSXTIpPool(NSXTBaseRealizableResource):\n    @staticmethod\n    def get_resource_spec():\n        ip_pool_arg_spec = {}\n        return ip_pool_arg_spec\n\n    @staticmethod\n    def get_resource_base_url(baseline_args=None):\n        return IP_POOL_URL\n\n    def update_parent_info(self, parent_info):\n        parent_info[\"ip_pool_id\"] = self.id\n\n    class NSXTIpAddressPoolBlockSubnet(NSXTBaseRealizableResource):\n        def get_spec_identifier(self):\n            return (NSXTIpPool.NSXTIpAddressPoolBlockSubnet.\n                    get_spec_identifier())\n\n        @classmethod\n        def get_spec_identifier(cls):\n            return \"pool_block_subnets\"\n\n        @staticmethod\n        def get_resource_spec():\n            ip_addr_pool_blk_subnet_arg_spec = {}\n            ip_addr_pool_blk_subnet_arg_spec.update(\n                ip_block_id=dict(\n                    required=False,\n                    type='str'\n                ),\n                ip_block_display_name=dict(\n                    required=False,\n                    type='str'\n                ),\n                auto_assign_gateway=dict(\n                    required=False,\n                    type='bool'\n                ),\n                size=dict(\n                    required=True,\n                    type='int'\n                ),\n                start_ip=dict(\n                    required=False,\n                    type='str'\n                ),\n            )\n            return ip_addr_pool_blk_subnet_arg_spec\n\n        @staticmethod\n        def get_resource_base_url(parent_info):\n            return IP_ADDRESS_POOL_SUBNET_URL.format(\n                parent_info[\"ip_pool_id\"]\n            )\n\n        def update_resource_params(self, nsx_resource_params):\n            # ip_block is a required attr\n            ip_block_id = self.get_id_using_attr_name_else_fail(\n                \"ip_block\", nsx_resource_params,\n                IP_BLOCK_URL, \"IP Block\")\n            nsx_resource_params[\"ip_block_path\"] = (\n                IP_BLOCK_URL + \"/\" + ip_block_id)\n\n            nsx_resource_params[\"resource_type\"] = \"IpAddressPoolBlockSubnet\"\n\n    class NSXTIpAddressPoolStaticSubnet(NSXTBaseRealizableResource):\n        def get_spec_identifier(self):\n            return (NSXTIpPool.NSXTIpAddressPoolStaticSubnet.\n                    get_spec_identifier())\n\n        @classmethod\n        def get_spec_identifier(cls):\n            return \"pool_static_subnets\"\n\n        @staticmethod\n        def get_resource_spec():\n            ip_addr_pool_static_subnet_arg_spec = {}\n            ip_addr_pool_static_subnet_arg_spec.update(\n                auto_assign_gateway=dict(\n                    required=False,\n                    type='bool'\n                ),\n                allocation_ranges=dict(\n                    required=True,\n                    elements='dict',\n                    type='list',\n                    options=dict(\n                        start=dict(\n                            required=True,\n                            type='str'\n                        ),\n                        end=dict(\n                            required=True,\n                            type='str'\n                        ),\n                    )\n                ),\n                cidr=dict(\n                    required=True,\n                    type='str'\n                ),\n                dns_nameservers=dict(\n                    required=False,\n                    elements='str',\n                    type='list'\n                ),\n                dns_suffix=dict(\n                    required=False,\n                    type='str'\n                ),\n                gateway_ip=dict(\n                    required=False,\n                    type='str'\n                ),\n            )\n            return ip_addr_pool_static_subnet_arg_spec\n\n        @staticmethod\n        def get_resource_base_url(parent_info):\n            return IP_ADDRESS_POOL_SUBNET_URL.format(\n                parent_info[\"ip_pool_id\"]\n            )\n\n        def update_resource_params(self, nsx_resource_params):\n            nsx_resource_params[\"resource_type\"] = \"IpAddressPoolStaticSubnet\"\n\n\nif __name__ == '__main__':\n    ip_pool = NSXTIpPool()\n    ip_pool.realize()\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_ip_pool_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_ip_pools_facts\nshort_description: List IP Pools\ndescription: Returns information about the configured IP address pools. Information\n             includes the display name and description of the pool and the details of\n             each of the subnets in the pool, including the DNS servers, allocation\n             ranges, gateway, and CIDR subnet address.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: List IP Pools\n  nsxt_ip_pools_facts:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n'''\n\nRETURN = '''# '''\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/policy/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(f\"{manager_url}/infra/ip-blocks\", headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing list of ip pools. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_l2_bridge_ep_profile.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_policy_l2_bridge_ep_profile\nshort_description: Create or Delete a Policy L2 Bridge Endpoint Profile\ndescription:\n    Creates or deletes a Policy L2 Bridge Endpoint Profile\n    Required attributes include id and display_name.\nversion_added: \"2.9\"\nauthor: Gautam Verma\nextends_documentation_fragment:\n    - vmware.ansible_for_nsxt.vmware_nsxt\noptions:\n    id:\n        description: The id of the Policy L2 Bridge Endpoint Profile\n        required: false\n        type: str\n    description:\n        description: Resource description.\n        type: str\n    edge_nodes_info:\n        description:\n            - List of dicts that comprise of information to form policy paths\n              to edge nodes. Edge allocation for L2 bridging\n            - Minimim 1 and Maximum 2 list elements\n        type: list\n        element: dict\n        suboptions:\n            site_id:\n                description: site_id where edge node is located\n                default: default\n                type: str\n            enforcementpoint_id:\n                description: enforcementpoint_id where edge node is\n                            located\n                default: default\n                type: str\n            edge_cluster_id:\n                description: edge_cluster_id where edge node is located\n                type: str\n            edge_cluster_display_name:\n                description:\n                    - display name of the edge cluster\n                    - either this or edge_cluster_id must be specified. If both\n                      are specified, edge_cluster_id takes precedence\n                type: str\n            edge_node_id:\n                description: ID of the edge node\n                type: str\n            edge_node_display_name:\n                description:\n                    - Display name of the edge node.\n                    - either this or edge_node_id must be specified. If both\n                     are specified, edge_node_id takes precedence\n                type: str\n    failover_mode:\n        description: Failover mode for the edge bridge cluster\n        type: str\n        default: PREEMPTIVE\n        choices:\n            - PREEMPTIVE\n            - NON_PREEMPTIVE\n    ha_mode:\n        description: High avaialability mode can be active-active or\n                     active-standby. High availability mode cannot be modified\n                     after realization\n        type: str\n        default: ACTIVE_STANDBY\n        choices:\n            - ACTIVE_STANDBY\n'''\n\nEXAMPLES = '''\n- name: create L2 Bridge Endpoint Profile\n  nsxt_policy_l2_bridge_ep_profile:\n    hostname: \"10.10.10.10\"\n    nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n    nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n    validate_certs: False\n    id: test-ep-profile\n    display_name: test-ep-profile\n    state: present\n    edge_nodes_info:\n        - edge_cluster_display_name: edge-cluster-1\n          edge_node_id: 123471da-3823-11ea-9170-000c291a8262\n    failover_mode: PREEMPTIVE\n    ha_mode: ACTIVE_STANDBY\n    tags:\n    - tag: \"my-tag\"\n      scope: \"my-scope\"\n'''\n\nRETURN = '''# '''\n\nimport json\nimport time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_base_resource import NSXTBaseRealizableResource\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import (\n    EDGE_CLUSTER_URL, EDGE_NODE_URL, L2_BRIDGE_EP_PROFILE_URL)\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.policy_resource_specs.l2_bridge_ep_profile import SPEC as L2BridgeEpProfileSpec\nfrom ansible.module_utils._text import to_native\n\n\nclass NSXTL2BridgeEpProfile(NSXTBaseRealizableResource):\n    @staticmethod\n    def get_resource_spec():\n        return L2BridgeEpProfileSpec\n\n    @staticmethod\n    def get_resource_base_url(baseline_args=None):\n        return L2_BRIDGE_EP_PROFILE_URL.format(\n            baseline_args['site_id'], baseline_args['enforcementpoint_id'])\n\n    def update_resource_params(self, nsx_resource_params):\n        nsx_resource_params.pop('site_id')\n        nsx_resource_params.pop('enforcementpoint_id')\n\n        edge_nodes_info = nsx_resource_params.pop(\n            \"edge_nodes_info\")\n        nsx_resource_params[\"edge_paths\"] = []\n        for edge_node_info in edge_nodes_info:\n            site_id = edge_node_info['site_id']\n            enforcementpoint_id = edge_node_info['enforcementpoint_id']\n            edge_cluster_base_url = (\n                EDGE_CLUSTER_URL.format(site_id, enforcementpoint_id))\n            edge_cluster_id = self.get_id_using_attr_name_else_fail(\n                \"edge_cluster\", edge_node_info,\n                edge_cluster_base_url, \"Edge Cluster\")\n            edge_node_base_url = EDGE_NODE_URL.format(\n                site_id, enforcementpoint_id, edge_cluster_id)\n            edge_node_id = self.get_id_using_attr_name_else_fail(\n                \"edge_node\", edge_node_info,\n                edge_node_base_url, \"Edge Node\")\n            nsx_resource_params[\"edge_paths\"].append(\n                edge_node_base_url + \"/\" + edge_node_id)\n\n\nif __name__ == '__main__':\n    l2_bridge_ep_profile = NSXTL2BridgeEpProfile()\n    l2_bridge_ep_profile.realize(baseline_arg_names=[\n        'site_id', 'enforcementpoint_id'])\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_security_policy.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_policy_security_policy\nshort_description: Create or Delete a Policy Security Policy\ndescription:\n    Creates or deletes a Policy Security Policy.\n    Required attributes include id and display_name.\nversion_added: \"2.8\"\nauthor: Gautam Verma\nextends_documentation_fragment:\n    - vmware.ansible_for_nsxt.vmware_nsxt\noptions:\n    id:\n        description: The id of the Policy Security Policy.\n        required: false\n        type: str\n    description:\n        description: Security Policy description.\n        type: str\n    domain_id:\n        description: The domain id where the Security Policy is realized.\n        type: str\n        required: true\n    category:\n        description:\n            - A way to classify a security policy, if needed.\n            - Distributed Firewall\n                - Policy framework provides five pre-defined categories for\n                classifying a security policy. They are \"Ethernet\",Emergency\",\n                \"Infrastructure\", \"Environment\" and \"Application\". There is a\n                pre-determined order in which the policy framework manages the\n                priority of these security policies. Ethernet category is for\n                supporting layer 2 firewall rules. The other four categories\n                are applicable for layer 3 rules. Amongst them, the Emergency\n                category has the highest priority followed by Infrastructure,\n                Environment and then Application rules. Administrator can\n                choose to categorize a security policy into the above\n                categories or can choose to leave it empty. If empty it will\n                have the least precedence w.r.t the above four categories.\n            - Edge Firewall\n                - Policy Framework for Edge Firewall provides six pre-defined\n                categories \"Emergency\", \"SystemRules\", \"SharedPreRules\",\n                \"LocalGatewayRules\", \"AutoServiceRules\" and\n                \"Default\", in order of priority of rules.\n                All categories are allowed for Gatetway Policies\n                that belong to 'default' Domain. However, for\n                user created domains, category is restricted to\n                \"SharedPreRules\" or \"LocalGatewayRules\" only.\n                Also, the users can add/modify/delete rules from\n                only the \"SharedPreRules\" and \"LocalGatewayRules\"\n                categories. If user doesn't specify the category\n                then defaulted to \"Rules\". System generated\n                category is used by NSX created rules, for\n                example BFD rules. Autoplumbed category used by\n                NSX verticals to autoplumb data path rules.\n                Finally, \"Default\" category is the placeholder\n                default rules with lowest in the order of priority.\n        type: str\n    comments:\n        type: str\n        description: SecurityPolicy lock/unlock comments\n    connectivity_strategy:\n        type: str\n        description:\n            - Connectivity strategy applicable for this SecurityPolicy\n            - This field indicates the default connectivity policy for the\n              security policy. Based on the connectivitiy strategy, a default\n              rule for this security policy will be created. An appropriate\n              action will be set on the rule based on the value of the\n              connectivity strategy. If NONE is selected or no connectivity\n              strategy is specified, then no default rule for the security\n              policy gets created. The default rule that gets created will be a\n              any-any rule and applied to entities specified in the scope of\n              the security policy. Specifying the connectivity_strategy without\n              specifying the scope is not allowed. The scope has to be a\n              Group and one cannot specify IPAddress directly in the group that\n              is used as scope. This default rule is only applicable for the\n              Layer3 security policies\n            - WHITELIST - Adds a default drop rule. Administrator can then use\n              \"allow\" rules (aka whitelist) to allow traffic between groups\n            - BLACKLIST - Adds a default allow rule. Admin can then use \"drop\"\n              rules (aka blacklist) to block traffic between groups\n            - WHITELIST_ENABLE_LOGGING - Whitelising with logging enabled\n            - BLACKLIST_ENABLE_LOGGING - Blacklisting with logging enabled\n            - NONE - No default rule is created\n    locked:\n        type: bool\n        description:\n            - Lock a security policy\n            - Indicates whether a security policy should be locked. If the\n              security policy is locked by a user, then no other user would\n              be able to modify this security policy. Once the user releases\n              the lock, other users can update this security policy.\n    scheduler_path:\n        type: str\n        description:\n            - Path to the scheduler for time based scheduling\n            - Provides a mechanism to apply the rules in this policy for a\n              specified time duration.\n    scope:\n        description: The list of group paths where the rules in this\n                     policy will get applied. This scope will take\n                     precedence over rule level scope. Supported only\n                     for security policies.\n        type: list\n    sequence_number:\n        description: Sequence number to resolve conflicts across Domains\n        type: int\n    stateful:\n        type: bool\n        description:\n            - Stateful nature of the entries within this security policy.\n            - Stateful or Stateless nature of security policy is enforced\n              on all rules in this security policy. When it is stateful, the\n              state of the network connects are tracked and a stateful packet\n              inspection is performed.\n            - Layer3 security policies can be stateful or stateless.\n              By default, they are stateful.\n            - Layer2 security policies can only be stateless.\n    rules:\n        description: Rules that are a part of this SecurityPolicy\n        type: list\n        suboptions:\n            action:\n                description: The action to be applied to all the\n                             services\n                type: str\n                choices:\n                    - \"ALLOW\"\n                    - \"DROP\"\n                    - \"REJECT\"\n            description:\n                description: Description of this resource\n                type: str\n            destination_groups:\n                description: Destination group paths\n                type: list\n                required: true\n            destinations_excluded:\n                description: Negation of destination groups\n\n                             If set to true, the rule gets applied on\n                             all the groups that are NOT part of the\n                             destination groups. If false, the rule\n                             applies to the destination groups.\n                type: bool\n                default: false\n            direction:\n                description: Define direction of traffic.\n                type: str\n                choices:\n                    - IN\n                    - OUT\n                    - IN_OUT\n            disabled:\n                description: Flag to disable the rule\n                type: bool\n                default: false\n            display_name:\n                description: Identifier to use when displaying entity\n                             in logs or GUI.\n\n                             Defaults to ID if not set\n                type: str\n            id:\n                description: Unique identifier of this resource\n                type: str\n                required: true\n            ip_protocol:\n                description:\n                    - IPv4 vs IPv6 packet type\n                    - Type of IP packet that should be matched while enforcing\n                      the rule. The value is set to IPV4_IPV6 for Layer3 rule\n                      if not specified. For Layer2/Ether rule the value must be\n                      null.\n                type: str\n                choices:\n                    - IPV4\n                    - IPV6\n                    - IPV4_IPV6\n            logged:\n                description: Flag to enable packet logging.\n                             Default is disabled.\n                type: bool\n                default: false\n            notes:\n                description: Text for additional notes on changes\n                type: str\n            profiles:\n                description:\n                    - Layer 7 service profiles\n                    - Holds the list of layer 7 service profile paths. These\n                      profiles accept attributes and sub-attributes of various\n                      network services (e.g. L4 AppId, encryption algorithm,\n                      domain name, etc) as key value pairs\n                type: list\n            scope:\n                description: The list of policy paths where the rule is applied\n                             LR/Edge/T0/T1/LRP etc. Note that a given rule can\n                             be applied on multiple LRs/LRPs\n                type: list\n            sequence_number:\n                description: Sequence number of the this Rule\n                type: int\n            service_entries:\n                description:\n                    - Raw services\n                    - In order to specify raw services this can be used,\n                      along with services which contains path to services.\n                      This can be empty or null\n                type: list\n                elements: dict\n            services:\n                description: Paths of services\n                             In order to specify all services, use the\n                             constant \"ANY\". This is case insensitive.\n                             If \"ANY\" is used, it should be the ONLY\n                             element in the services array. Error will\n                             be thrown if ANY is used in conjunction\n                             with other values.\n                type: list\n                required: true\n            source_groups:\n                description: Source group paths\n                type: list\n                required: true\n            sources_excluded:\n                description: Negation of source groups\n\n                             If set to true, the rule gets applied on\n                             all the groups that are NOT part of the\n                             source groups. If false, the rule applies\n                             to the source groups\n                type: bool\n                default: false\n            tag:\n                description:\n                    - Tag applied on the rule\n                    - User level field which will be printed in CLI and packet\n                      logs.\n                type: str\n            tags:\n                description: Opaque identifiers meaningful to the API user\n                type: list\n                elements: dict\n                suboptions:\n                    scope:\n                        description: Tag scope\n                        type: str\n                    tag:\n                        description: Tag value\n                        type: str\n    tcp_strict:\n        type: bool\n        description:\n            - Enforce strict tcp handshake before allowing data packets\n            - Ensures that a 3 way TCP handshake is done before the data\n              packets are sent.\n            - tcp_strict=true is supported only for stateful security policies\n'''\n\nEXAMPLES = '''\n- name: create Security Policy\n  nsxt_policy_security_policy:\n    hostname: \"10.10.10.10\"\n    nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n    nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n    validate_certs: False\n    id: test-sec-pol\n    display_name: test-sec-pol\n    state: \"present\"\n    domain_id: \"default\"\n    locked: True\n    rules:\n      - action: \"ALLOW\"\n        description: \"example-rule\"\n        sequence_number: 1\n        display_name: \"test-example-rule\"\n        id: \"test-example-rule\"\n        source_groups: [\"/infra/domains/vmc/groups/dbgroup\"]\n        destination_groups: [\"/infra/domains/vmc/groups/appgroup\"]\n        services: [\"/infra/services/HTTP\", \"/infra/services/CIM-HTTP\"]\n        tag: my-tag\n        tags:\n          - scope: scope-1\n            tag: tag-1\n        logged: True\n        notes: dummy-notes\n        ip_protocol: IPV4_IPV6\n        scope: my-scope\n        profiles: \"encryption algorithm\"\n'''\n\nRETURN = '''# '''\n\nimport json\nimport time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_base_resource import NSXTBaseRealizableResource\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import SECURITY_POLICY_URL\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.policy_resource_specs.security_policy import SPEC as SecurityPolicySpec\nfrom ansible.module_utils._text import to_native\n\n\nclass NSXTSecurityPolicy(NSXTBaseRealizableResource):\n    @staticmethod\n    def get_resource_spec():\n        return SecurityPolicySpec\n\n    @staticmethod\n    def get_resource_base_url(baseline_args):\n        return SECURITY_POLICY_URL.format(\n            baseline_args[\"domain_id\"])\n\n    def update_resource_params(self, nsx_resource_params):\n        nsx_resource_params.pop('domain_id')\n\n\nif __name__ == '__main__':\n    sec_policy = NSXTSecurityPolicy()\n    sec_policy.realize(baseline_arg_names=[\"domain_id\"])\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_segment.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_policy_segment\nshort_description: Create or Delete a Policy Segment\ndescription:\n    Creates or deletes a Policy Segment.\n    Required attributes include id and display_name.\n    If the specified TransportZone is of VLAN type, a vlan_id is also required.\nversion_added: \"2.8\"\nauthor: Gautam Verma\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        type: str\n    password:\n        description:\n            - The password to authenticate with the NSX manager.\n            - Must be specified if username is specified\n        type: str\n    ca_path:\n        description: Path to the CA bundle to be used to verify host's SSL\n                     certificate\n        type: str\n    nsx_cert_path:\n        description: Path to the certificate created for the Principal\n                     Identity using which the CRUD operations should be\n                     performed\n        type: str\n    nsx_key_path:\n        description:\n            - Path to the certificate key created for the Principal Identity\n              using which the CRUD operations should be performed\n            - Must be specified if nsx_cert_path is specified\n        type: str\n    request_headers:\n        description: HTTP request headers to be sent to the host while making\n                     any request\n        type: dict\n    display_name:\n        description:\n            - Display name.\n            - If resource ID is not specified, display_name will be used as ID.\n        required: false\n        type: str\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'.\n                    'present' is used to create or update resource.\n                    'absent' is used to delete resource.\"\n        required: true\n    validate_certs:\n        description: Enable server certificate verification.\n        type: bool\n        default: False\n    tags:\n        description: Opaque identifiers meaningful to the API user.\n        type: dict\n        suboptions:\n            scope:\n                description: Tag scope.\n                required: true\n                type: str\n            tag:\n                description: Tag value.\n                required: true\n                type: str\n    create_or_update_subresource_first:\n        type: bool\n        default: false\n        description:\n            - Can be used to create subresources first.\n            - Can be specified for each subresource.\n    delete_subresource_first:\n        type: bool\n        default: true\n        description:\n            - Can be used to delete subresources first.\n            - Can be specified for each subresource.\n    achieve_subresource_state_if_del_parent:\n        type: bool\n        default: false\n        description:\n            - Can be used to achieve the state of subresources even if\n              the parent(base) resource's state is absent.\n            - Can be specified for each subresource.\n    do_wait_till_create:\n        type: bool\n        default: false\n        description:\n            - Can be used to wait for the realization of subresource before the\n              request to create the next resource is sent to the Manager.\n            - Can be specified for each subresource.\n    id:\n        description: The id of the Policy Segment.\n        required: false\n        type: str\n    description:\n        description: Segment description.\n        type: str\n    address_bindings:\n        description: Address bindings for the Segment\n        type: list\n        elements: dict\n        suboptions:\n            ip_address:\n                description: IP Address for port binding\n                type: str\n            mac_address:\n                description: Mac address for port binding\n                type: str\n            vlan_id:\n                description: VLAN ID for port binding\n                type: int\n    admin_state:\n        description: Represents Desired state of the Segment\n        type: str\n        choices:\n            - UP\n            - DOWN\n        default: UP\n    advanced_config:\n        description: Advanced configuration for Segment.\n        type: dict\n        suboptions:\n            address_pool_display_name:\n                description:\n                    - IP address pool display name\n                    - Either this or address_pool_id must be specified. If both\n                      are specified, address_pool_id takes precedence\n                type: str\n            address_pool_id:\n                description:\n                    - IP address pool ID\n                    - Either this or address_pool_display_name must be\n                      specified. If both are specified, address_pool_id takes\n                      precedence\n                type: str\n            connectivity:\n                description: Connectivity configuration to manually connect\n                             (ON) or disconnect (OFF) a logical entity from\n                             network topology. Only valid for Tier1 Segment\n                type: str\n            hybrid:\n                description:\n                    - Flag to identify a hybrid logical switch\n                    - When set to true, all the ports created on this segment\n                      will behave in a hybrid fashion. The hybrid port\n                      indicates to NSX that the VM intends to operate in\n                      underlay mode, but retains the ability to forward egress\n                      traffic to the NSX overlay network. This property is only\n                      applicable for segment created with transport zone type\n                      OVERLAY_STANDARD. This property cannot be modified after\n                      segment is created.\n                type: bool\n            local_egress:\n                description:\n                    - Flag to enable local egress\n                    - This property is used to enable proximity routing with\n                      local egress. When set to true, logical router interface\n                      (downlink) connecting Segment to Tier0/Tier1 gateway is\n                      configured with prefix-length 32.\n                type: bool\n            local_egress_routing_policies:\n                description: An ordered list of routing policies to forward\n                             traffic to the next hop.\n                type: list\n                elements: dict\n                suboptions:\n                    nexthop_address:\n                        required: true\n                        description: Next hop address for proximity routing\n                        type: str\n                    prefix_list_paths:\n                        required: true\n                        description:\n                            - Policy path to prefix lists\n                            - max 1 element\n                            - The destination address of traffic matching a\n                              prefix-list is forwarded to the nexthop_address.\n                              Traffic matching a prefix list with Action DENY\n                              will be dropped. Individual prefix-lists\n                              specified could have different actions.\n                        type: list\n                        elements: str\n            multicast:\n                description:\n                    - Enable multicast on the downlink\n                    - Enable multicast for a segment. Only applicable for\n                      segments connected to Tier0 gateway.\n                type: bool\n            uplink_teaming_policy_name:\n                description:\n                    - Uplink Teaming Policy Name\n                    - The name of the switching uplink teaming policy for the\n                      Segment. This name corresponds to one of the switching\n                      uplink teaming policy names listed in TransportZone\n                      associated with the Segment. When this property is\n                      not specified, the segment will not have a teaming policy\n                      associated with it and the host switch's default teaming\n                      policy will be used by MP.\n                type: str\n    bridge_profiles:\n        description: Bridge Profile Configuration\n        type: list\n        elements: dict\n        suboptions:\n            bridge_profile_path:\n                description:\n                    - Policy path to L2 Bridge profile\n                    - Same bridge profile can be configured on different\n                      segments. Each bridge profile on a segment must unique.\n                type: str\n                required: true\n            uplink_teaming_policy_name:\n                description:\n                    - Uplink Teaming Policy Name\n                    - The name of the switching uplink teaming policy for the\n                      bridge endpoint. This name corresponds to one of the\n                      switching uplink teaming policy names listed in the\n                      transport zone. When this property is not specified, the\n                      teaming policy is assigned by MP.\n                type: str\n            vlan_ids:\n                description: VLAN specification for bridge endpoint. Either\n                             VLAN ID or VLAN ranges can be specified. Not both.\n                type: str\n            vlan_transport_zone_path:\n                description:\n                    - Policy path to VLAN Transport Zone\n                    - VLAN transport zone should belong to the enforcment-point\n                      as the transport zone specified in the segment.\n                type: str\n                required: true\n    connectivity_path:\n        description: Policy path to the connecting Tier-0 or Tier-1. Valid only\n                     for segments created under Infra\n        type: str\n    dhcp_config_path:\n        description:\n            - Policy path to DHCP configuration\n            - Policy path to DHCP server or relay configuration to use for all\n              IPv4 & IPv6 subnets configured on this segment.\n        type: str\n    extra_configs:\n        description:\n            - Extra configs on Segment\n            - This property could be used for vendor specific configuration in\n              key value string pairs, the setting in extra_configs will be\n              automatically inheritted by segment ports in the Segment.\n        type: list\n        elements: dict\n        suboptions:\n            config_pair:\n                description: Key value pair in string for the configuration\n                type: dict\n                required: true\n                suboptions:\n                    key:\n                        description: Key\n                        type: str\n                        required: true\n                    value:\n                        description: Value\n                        type: str\n                        required: true\n    l2_extension:\n        description: Configuration for extending Segment through L2 VPN\n        type: dict\n        suboptions:\n            l2vpn_paths:\n                description: Policy paths corresponding to the associated L2\n                             VPN sessions\n                type: list\n                elements: str\n            local_egress:\n                description: Local Egress\n                type: dict\n                suboptions:\n                    optimized_ips:\n                        description: Gateway IP for Local Egress. Local egress\n                                     is enabled only when this list is not\n                                     empty\n                        type: list\n                        elements: str\n            tunnel_id:\n                description: Tunnel ID\n                type: int\n    mac_pool_id:\n        description: Allocation mac pool associated with the Segment\n        type: str\n    metadata_proxy_paths:\n        description: Metadata Proxy Configuration Paths\n        type: list\n        elements: str\n    overlay_id:\n        description:\n            - Overlay connectivity ID for this Segment\n            - Used for overlay connectivity of segments. The overlay_id\n              should be allocated from the pool as definied by\n              enforcement-point. If not provided, it is auto-allocated from the\n              default pool on the enforcement-point\n        type: int\n    replication_mode:\n        description: Replication mode of the Segment\n        type: str\n        default: MTEP\n        choices:\n            - MTEP\n            - SOURCE\n    tier0_id:\n        description: The Uplink of the Policy Segment.\n                     Mutually exclusive with tier_1_id.\n        type: str\n    tier0_display_name:\n        description: Same as tier_0_id. Either one can be specified.\n                     If both are specified, tier_0_id takes\n                     precedence.\n        type: str\n    tier1_id:\n        description: The Uplink of the Policy Segment.\n                     Mutually exclusive with tier_0_id but takes precedence.\n        type: str\n    tier1_display_name:\n        description: Same as tier_1_id. Either one can be specified.\n                     If both are specified, tier_1_id takes\n                     precedence.\n        type: str\n    domain_name:\n        description: Domain name associated with the Policy Segment.\n        type: str\n    transport_zone_id:\n        description: The TZ associated with the Policy Segment.\n        type: str\n    transport_zone_display_name:\n        description: Same as transport_zone_id. Either one can be specified.\n                     If both are specified, transport_zone_id takes\n                     precedence.\n        type: str\n    enforcementpoint_id:\n        description: The EnforcementPoint ID where the TZ is located.\n                     Required if transport_zone_id is specified.\n        default: default\n        type: str\n    site_id:\n        description: The site ID where the EnforcementPoint is located.\n                     Required if transport_zone_id is specified.\n        default: default\n        type: str\n    vlan_ids:\n        description: VLAN ids for a VLAN backed Segment.\n                     Can be a VLAN id or a range of VLAN ids specified with '-'\n                     in between.\n        type: list\n    subnets:\n        description: Subnets that belong to this Policy Segment.\n        type: dict\n        suboptions:\n            dhcp_config:\n                description: Additional DHCP configuration for current subnet\n                type: dict\n                suboptions:\n                    dns_servers:\n                        description: IP address of DNS servers for subnet. DNS\n                                     server IP address must belong to the same\n                                     address family as segment gateway_address\n                                     property\n                        type: list\n                    lease_time:\n                        description:\n                            - DHCP lease time in seconds. When specified, this\n                              property overwrites lease time configured DHCP\n                              server config\n                            - Minimum: 60\n                            - Maximum: 4294967295\n                            - Default: \"86400\"\n                        type: int\n                    resource_type:\n                        description: Resource type\n                        choices:\n                            - SegmentDhcpV4Config\n                            - SegmentDhcpV6Config\n                        type: str\n                    server_address:\n                        description: IP address of the DHCP server in CIDR\n                                     format. The server_address is mandatory in\n                                     case this segment has provided a\n                                     dhcp_config_path and it represents a DHCP\n                                     server config. If this SegmentDhcpConfig\n                                     is a SegmentDhcpV4Config, the address must\n                                     be an IPv4 address. If this is a\n                                     SegmentDhcpV6Config, the address must\n                                     be an IPv6 address. This address must not\n                                     overlap the ip-ranges of the subnet, or\n                                     the gateway address of the subnet, or the\n                                     DHCP static-binding addresses of this\n                                     segment\n                        type: str\n                    options:\n                        description:\n                            - Property of SegmentDhcpV4Config\n                            - IPv4 DHCP options for segment subnet\n                        type: dict\n                        suboptions:\n                            option121:\n                                description: DHCP option 121 to define\n                                             classless static routes\n                                type: dict\n                                suboptions:\n                                    static_routes:\n                                        description: Classless static route of\n                                                     DHCP option 121\n                                        type: list\n                                        elements: dict\n                                        suboptions:\n                                            network:\n                                                description: Destination\n                                                             network in CIDR\n                                                             format\n                                                type: str\n                                                required: true\n                                            next_hop:\n                                                description: IP address of next\n                                                             hop of the route\n                                                type: str\n                                                required: true\n                            others:\n                                description:\n                                    Other DHCP options\n                                    To define DHCP options other than option\n                                    121 in generic format. Please note, only\n                                    the following options can be defined in\n                                    generic format. Those other options will be\n                                    accepted without validation but will not\n                                    take effect\n                                    --------------------------\n                                    Code Name\n                                    --------------------------\n                                    2 Time Offset\n                                    6 Domain Name Server\n                                    13 Boot File Size\n                                    19 Forward On/Off\n                                    26 MTU Interface\n                                    28 Broadcast Address\n                                    35 ARP Timeout\n                                    40 NIS Domain\n                                    41 NIS Servers\n                                    42 NTP Servers\n                                    44 NETBIOS Name Srv\n                                    45 NETBIOS Dist Srv\n                                    46 NETBIOS Node Type\n                                    47 NETBIOS Scope\n                                    58 Renewal Time\n                                    59 Rebinding Time\n                                    64 NIS+-Domain-Name\n                                    65 NIS+-Server-Addr\n                                    66 TFTP Server-Name (used by PXE)\n                                    67 Bootfile-Name (used by PXE)\n                                    93 PXE: Client system architecture\n                                    94 PXE: Client NDI\n                                    97 PXE: UUID/UNDI\n                                    117 Name Service Search\n                                    119 Domain Search\n                                    150 TFTP server address (used by PXE)\n                                    175 Etherboot\n                                    209 PXE Configuration File\n                                    210 PXE Path Prefix\n                                    211 PXE Reboot Time\n                                type: list\n                                elements: dict\n                                suboptions:\n                                    code:\n                                        description: DHCP option code, [0-255]\n                                        type: int\n                                        required: true\n                                    values:\n                                        description: DHCP option value\n                                        type: list\n                                        required: true\n                    domain_names:\n                        description:\n                            - Property of SegmentDhcpV6Config\n                            - Domain names for subnet\n                        type: list\n                    excluded_ranges:\n                        description:\n                            - Property of SegmentDhcpV6Config\n                            - Excluded IPv6 addresses to define dynamic ip\n                              allocation ranges\n                        type: list\n                    preferred_time:\n                            - Property of SegmentDhcpV6Config\n                            - The length of time that a valid address is\n                              preferred. When the preferred lifetime expires,\n                              the address becomes deprecated\n                            - Minimum: 60\n                            - Maximum: 4294967295\n                        type: int\n                    sntp_servers:\n                        description:\n                            - Property of SegmentDhcpV6Config\n                            - IPv6 address of SNTP servers for subnet\n                        type: list\n            dhcp_ranges:\n                description: DHCP address ranges for dynamic IP allocation.\n                             DHCP address ranges are used for dynamic IP\n                             allocation. Supports address range and CIDR\n                             formats. First valid host address from the first\n                             value is assigned to DHCP server IP address.\n                             Existing values cannot be deleted or modified, but\n                             additional DHCP ranges can be added.\n                             Formats, e.g. 10.12.2.64/26, 10.12.2.2-10.12.2.50\n                type: list\n            gateway_address:\n                description: Gateway IP address.\n                             Gateway IP address in CIDR format for both IPv4\n                             and IPv6.\n                required: True\n                type: str\n    segment_ports:\n        type: list\n        description:\n            - Add the Segment Ports to be create, updated, or deleted in this\n              section\n        element: dict\n        suboptions:\n            address_bindings:\n                description: Static address binding used for the port.\n                type: list\n                elements: dict\n                suboptions:\n                ip_address:\n                    description: IP Address for port binding.\n                    type: str\n                mac_address:\n                    description: Mac address for port binding.\n                    type: str\n                vlan_id:\n                    description: VLAN ID for port binding.\n                    type: str\n            attachment:\n                description: VIF attachment.\n                type: dict\n                suboptions:\n                    allocate_addresses:\n                        description: Indicate how IP will be\n                                    allocated for the port.\n                        type: str\n                        choices:\n                            - IP_POOL\n                            - MAC_POOL\n                            - BOTH\n                            - NONE\n                    app_id:\n                        description: ID used to identify/look up a\n                                     child attachment behind a\n                                     parent attachment.\n                        type: str\n                    context_id:\n                        description: Parent VIF ID if type is CHILD,\n                                    Transport node ID if type is\n                                    INDEPENDENT.\n                        type: str\n                    id:\n                        description: VIF UUID on NSX Manager.\n                        type: str\n                    traffic_tag:\n                        description:\n                            - VLAN ID\n                            - Not valid when type is INDEPENDENT, mainly\n                              used to identify traffic from different ports\n                              in container use case\n                        type: int\n                    type:\n                        description: Type of port attachment.\n                        type: str\n                        choices:\n                            - PARENT\n                            - CHILD\n                            - INDEPENDENT\n            display_name:\n                description:\n                    - Segment Port display name.\n                    - Either this or id must be specified. If both are\n                      specified, id takes precedence.\n                required: false\n                type: str\n            description:\n                description:\n                    - Segment description.\n                type: str\n            do_wait_till_create:\n                type: bool\n                default: false\n                description: Can be used to wait for the realization of\n                             subresource before the request to create the next\n                             resource is sent to the Manager\n            extra_configs:\n                description:\n                    - Extra configs on segment port\n                    - This property could be used for vendor specific\n                      configuration in key value string pairs. Segment port\n                      setting will override segment setting if the same key was\n                      set on both segment and segment port.\n                type: list\n                element: dict\n                suboptions:\n                    config_pair:\n                        description: Key value pair in string for the\n                                     configuration\n                        type: dict\n                        required: true\n                        suboptions:\n                            key:\n                                description: Key\n                                type: str\n                                required: true\n                            value:\n                                description: Value\n                                type: str\n                                required: true\n            id:\n                description: The id of the Policy Segment Port.\n                required: false\n                type: str\n            ignored_address_bindings:\n                description:\n                    - Address bindings to be ignored by IP Discovery module\n                      IP Discovery module uses various mechanisms to discover\n                      address bindings being used on each segment port. If a\n                      user would like to ignore any specific discovered address\n                      bindings or prevent the discovery of a particular set of\n                      discovered bindings, then those address bindings can be\n                      provided here. Currently IP range in CIDR format is not\n                      supported.\n                type: dict\n                suboptions:\n                ip_address:\n                    description: IP Address for port binding.\n                    type: str\n                mac_address:\n                    description: Mac address for port binding.\n                    type: str\n                vlan_id:\n                    description: VLAN ID for port binding.\n                    type: str\n            init_state:\n                description:\n                    - Initial state of this logical ports\n                    - Set initial state when a new logical port is created.\n                      'UNBLOCKED_VLAN' means new port will be unblocked on\n                      traffic in creation, also VLAN will be set with\n                      corresponding logical switch setting. This port setting\n                      can only be configured at port creation, and cannot be\n                      modified.\n                type: str\n                choices:\n                    - UNBLOCKED_VLAN\n                default: UNBLOCKED_VLAN\n            state:\n                choices:\n                    - present\n                    - absent\n                description:\n                    - State can be either 'present' or 'absent'. 'present' is\n                      used to create or update resource. 'absent' is used to\n                      delete resource\n                    - Required if I(id != null)\n                required: true\n            tags:\n                description: Opaque identifiers meaningful to the API user.\n                type: dict\n                suboptions:\n                    scope:\n                        description: Tag scope.\n                        required: true\n                        type: str\n                    tag:\n                        description: Tag value.\n                        required: true\n                        type: str\n'''\n\nEXAMPLES = '''\n- name: create Segment\n  nsxt_policy_segment:\n    hostname: \"10.10.10.10\"\n    nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n    nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n    validate_certs: False\n    display_name: test-seg-4\n    state: present\n    domain_name: dn1\n    transport_zone_display_name: \"1-transportzone-730\"\n    replication_mode: \"SOURCE\"\n    address_bindings:\n      - ip_address: \"10.1.2.11\"\n    advanced_config:\n      address_pool_display_name: small-2-pool\n      connectivity: \"OFF\"\n      hybrid: False\n      local_egress: True\n    admin_state: UP\n    connectivity_path: \"/infra/tier-1s/d082bc25-a9b2-4d13-afe5-d3cecad4b854\"\n    subnets:\n      - gateway_address: \"40.1.1.1/16\"\n    segment_ports:\n      - display_name: test-sp-1\n        state: present\n        tags:\n          - scope: \"scope-1\"\n            tag: \"tag-2\"\n        extra_configs:\n          - config_pair:\n              key: key\n              value: value\n        ignored_address_bindings:\n          - ip_address: \"10.1.2.122\"\n      - display_name: test-sp-2\n        state: present\n      - display_name: test-sp-3\n        state: present\n'''\n\nRETURN = '''# '''\n\nimport json\nimport time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_base_resource import NSXTBaseRealizableResource\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import (\n    SEGMENT_PORT_URL, SEGMENT_URL, TIER_0_URL, TIER_1_URL, TRANSPORT_ZONE_URL,\n    IP_POOL_URL)\nfrom ansible.module_utils._text import to_native\n\n\nclass NSXTSegment(NSXTBaseRealizableResource):\n    @staticmethod\n    def get_resource_spec():\n        segment_arg_spec = {}\n        segment_arg_spec.update(\n            address_bindings=dict(\n                required=False,\n                type='list',\n                elements='dict',\n                options=dict(\n                    ip_address=dict(\n                        required=False,\n                        type='str'\n                    ),\n                    mac_address=dict(\n                        required=False,\n                        type='str'\n                    ),\n                    vlan_id=dict(\n                        required=False,\n                        type='int'\n                    )\n                )\n            ),\n            admin_state=dict(\n                type='str',\n                choices=['UP', 'DOWN'],\n                default='UP'\n            ),\n            advanced_config=dict(\n                required=False,\n                type='dict',\n                options=dict(\n                    address_pool_id=dict(\n                        required=False,\n                        type='str'\n                    ),\n                    address_pool_display_name=dict(\n                        required=False,\n                        type='str'\n                    ),\n                    connectivity=dict(\n                        default=\"ON\",\n                        type='str',\n                        choices=[\"ON\", \"OFF\"],\n                    ),\n                    hybrid=dict(\n                        required=False,\n                        type='bool',\n                        default=False\n                    ),\n                    local_egress=dict(\n                        required=False,\n                        type='bool',\n                        default=False\n                    ),\n                    local_egress_routing_policies=dict(\n                        required=False,\n                        type='list',\n                        elements='dict',\n                        options=dict(\n                            nexthop_address=dict(\n                                required=True,\n                                type='str'\n                            ),\n                            prefix_list_paths=dict(\n                                required=True,\n                                type='list',\n                                elements='str'\n                            ),\n                        )\n                    ),\n                    multicast=dict(\n                        required=False,\n                        type='bool'\n                    ),\n                    uplink_teaming_policy_name=dict(\n                        required=False,\n                        type='str'\n                    ),\n                )\n            ),\n            bridge_profiles=dict(\n                type='list',\n                elements='dict',\n                options=dict(\n                    bridge_profile_path=dict(\n                        type='str',\n                        required=True\n                    ),\n                    uplink_teaming_policy_name=dict(\n                        type='str'\n                    ),\n                    vlan_ids=dict(\n                        type='list',\n                        elements='str'\n                    ),\n                    vlan_transport_zone_path=dict(\n                        type='str',\n                        required=True\n                    ),\n                )\n            ),\n            connectivity_path=dict(\n                type='str'\n            ),\n            dhcp_config_path=dict(\n                type='str'\n            ),\n            domain_name=dict(\n                required=False,\n                type='str'\n            ),\n            enforcementpoint_id=dict(\n                required=False,\n                type='str',\n            ),\n            extra_configs=dict(\n                type='list',\n                elements='dict',\n                options=dict(\n                    config_pair=dict(\n                        type='dict',\n                        required=True,\n                        options=dict(\n                            key=dict(\n                                type='str',\n                                required=True\n                            ),\n                            value=dict(\n                                type='str',\n                                required=True\n                            )\n                        )\n                    ),\n                )\n            ),\n            l2_extension=dict(\n                type='dict',\n                options=dict(\n                    l2vpn_path=dict(\n                        type='str',\n                        required=True\n                    ),\n                    l2vpn_paths=dict(\n                        type='list',\n                        elements='str'\n                    ),\n                    local_egress=dict(\n                        type='dict',\n                        options=dict(\n                            optimized_ips=dict(\n                                type='list',\n                                elements='str'\n                            )\n                        )\n                    ),\n                    tunnel_id=dict(\n                        type='int'\n                    ),\n                )\n            ),\n            mac_pool_id=dict(\n                required=False,\n                type='str'\n            ),\n            metadata_proxy_paths=dict(\n                elements='str',\n                type='list'\n            ),\n            overlay_id=dict(\n                type='int'\n            ),\n            replication_mode=dict(\n                type='str',\n                default=\"MTEP\",\n                choices=[\"MTEP\", \"SOURCE\"]\n            ),\n            site_id=dict(\n                required=False,\n                type='str',\n            ),\n            subnets=dict(\n                required=False,\n                type='list',\n                elements='dict',\n                options=dict(\n                    dhcp_config=dict(\n                        required=False,\n                        type='dict',\n                        options=dict(\n                            dns_servers=dict(\n                                required=False,\n                                type='list',\n                            ),\n                            lease_time=dict(\n                                required=False,\n                                type='int',\n                            ),\n                            resource_type=dict(\n                                required=True,\n                                type='str',\n                                choices=[\n                                    'SegmentDhcpV4Config',\n                                    'SegmentDhcpV6Config']\n                            ),\n                            server_address=dict(\n                                required=False,\n                                type='str',\n                            ),\n                            options=dict(\n                                required=False,\n                                type='dict',\n                                suboptions=dict(\n                                    option121=dict(\n                                        required=False,\n                                        type='dict',\n                                        suboptions=dict(\n                                            static_routes=dict(\n                                                required=False,\n                                                type='list',\n                                                elements='dict',\n                                                suboptions=dict(\n                                                    network=dict(\n                                                        required=True,\n                                                    ),\n                                                    next_hop=dict(\n                                                        required=True,\n                                                    ),\n                                                ),\n                                            ),\n                                        ),\n                                    ),\n                                    others=dict(\n                                        required=False,\n                                        type='list',\n                                        elements='dict',\n                                        suboptions=dict(\n                                            code=dict(\n                                                required=True,\n                                                type='int',\n                                            ),\n                                            values=dict(\n                                                required=True,\n                                                type='list',\n                                            ),\n                                        ),\n                                    ),\n                                ),\n                            ),\n                            domain_names=dict(\n                                required=False,\n                                type='list',\n                            ),\n                            excluded_ranges=dict(\n                                required=False,\n                                type='list',\n                            ),\n                            preferred_time=dict(\n                                required=False,\n                                type='int',\n                            ),\n                            sntp_servers=dict(\n                                required=False,\n                                type='list',\n                            ),\n                        ),\n                    ),\n                    dhcp_ranges=dict(\n                        required=False,\n                        type='list'\n                    ),\n                    gateway_address=dict(\n                        required=True,\n                        type='str'\n                    )\n                )\n            ),\n            tier0_display_name=dict(\n                required=False,\n                type='str'\n            ),\n            tier0_id=dict(\n                required=False,\n                type='str'\n            ),\n            tier1_display_name=dict(\n                required=False,\n                type='str'\n            ),\n            tier1_id=dict(\n                required=False,\n                type='str'\n            ),\n            transport_zone_display_name=dict(\n                required=False,\n                type='str'\n            ),\n            transport_zone_id=dict(\n                required=False,\n                type='str'\n            ),\n            vlan_ids=dict(\n                required=False,\n                type='list'\n            ),\n        )\n        return segment_arg_spec\n\n    @staticmethod\n    def get_resource_base_url(baseline_args=None):\n        return SEGMENT_URL\n\n    def update_resource_params(self, nsx_resource_params):\n        if self.do_resource_params_have_attr_with_id_or_display_name(\n                \"tier0\"):\n            tier0_id = self.get_id_using_attr_name_else_fail(\n                \"tier0\", nsx_resource_params,\n                TIER_0_URL, \"Tier0\")\n            nsx_resource_params[\"connectivity_path\"] = (\n                TIER_0_URL + \"/\" + tier0_id)\n        elif self.do_resource_params_have_attr_with_id_or_display_name(\n                \"tier1\"):\n            tier1_id = self.get_id_using_attr_name_else_fail(\n                \"tier1\", nsx_resource_params,\n                TIER_1_URL, \"Tier1\")\n            nsx_resource_params[\"connectivity_path\"] = (\n                TIER_1_URL + \"/\" + tier1_id)\n\n        if self.do_resource_params_have_attr_with_id_or_display_name(\n                \"transport_zone\"):\n            site_id = nsx_resource_params.pop(\"site_id\", 'default')\n            enforcementpoint_id = nsx_resource_params.pop(\n                \"enforcementpoint_id\", 'default')\n            transport_zone_base_url = (\n                TRANSPORT_ZONE_URL.format(site_id, enforcementpoint_id))\n            transport_zone_id = self.get_id_using_attr_name_else_fail(\n                \"transport_zone\", nsx_resource_params,\n                transport_zone_base_url, \"Transport Zone\")\n            nsx_resource_params[\"transport_zone_path\"] = (\n                transport_zone_base_url + \"/\" + transport_zone_id)\n\n        if 'advanced_config' in nsx_resource_params and nsx_resource_params[\n                'advanced_config']:\n            address_pool_id = None\n            if nsx_resource_params['advanced_config'].get('address_pool_id'):\n                address_pool_id = nsx_resource_params['advanced_config'].pop(\n                    'address_pool_id')\n            elif nsx_resource_params['advanced_config'].get(\n                    'address_pool_display_name'):\n                address_pool_id = self.get_id_from_display_name(\n                    IP_POOL_URL, nsx_resource_params['advanced_config'][\n                        'address_pool_display_name'], \"Ip Pool\",\n                    ignore_not_found_error=False)\n                nsx_resource_params['advanced_config'].pop(\n                    'address_pool_display_name')\n            if address_pool_id:\n                address_pool_paths = [IP_POOL_URL + \"/\" + address_pool_id]\n                nsx_resource_params['advanced_config'][\n                    'address_pool_paths'] = address_pool_paths\n\n        self._updateSubnetsAsPerIpvType(nsx_resource_params)\n\n    def _updateSubnetsAsPerIpvType(self, nsx_resource_params):\n        subnets = nsx_resource_params.get('subnets', [])\n        for subnet in subnets:\n            dhcp_config = subnet.get('dhcp_config')\n            if dhcp_config:\n                if dhcp_config['resource_type'] == \"SegmentDhcpV4Config\":\n                    self._remove_ipv6_subnet_attrs(dhcp_config)\n                else:\n                    self._remove_ipv4_subnet_attrs(dhcp_config)\n\n    def _remove_ipv6_subnet_attrs(self, dhcp_config):\n        dhcp_config.pop('domain_names', None)\n        dhcp_config.pop('excluded_ranges', None)\n        dhcp_config.pop('preferred_time', None)\n        dhcp_config.pop('sntp_servers', None)\n\n    def _remove_ipv4_subnet_attrs(self, dhcp_config):\n        dhcp_config.pop('options', None)\n\n    def update_parent_info(self, parent_info):\n        parent_info[\"segment_id\"] = self.id\n\n    class NSXTSegmentPort(NSXTBaseRealizableResource):\n        def get_spec_identifier(self):\n            return NSXTSegment.NSXTSegmentPort.get_spec_identifier()\n\n        @classmethod\n        def get_spec_identifier(cls):\n            return \"segment_ports\"\n\n        @staticmethod\n        def get_resource_spec():\n            segment_port_arg_spec = {}\n            segment_port_arg_spec.update(\n                address_bindings=dict(\n                    required=False,\n                    type='list',\n                    elements='dict',\n                    options=dict(\n                        ip_address=dict(\n                            required=False,\n                            type='str'\n                        ),\n                        mac_address=dict(\n                            required=False,\n                            type='str'\n                        ),\n                        vlan_id=dict(\n                            required=False,\n                            type='int'\n                        )\n                    )\n                ),\n                admin_state=dict(\n                    required=False,\n                    type='str',\n                    default='UP',\n                    choices=['UP', 'DOWN']\n                ),\n                attachment=dict(\n                    required=False,\n                    type='dict',\n                    options=dict(\n                        allocate_addresses=dict(\n                            required=False,\n                            type='str',\n                            choices=['IP_POOL', 'MAC_POOL', 'BOTH', 'NONE']\n                        ),\n                        app_id=dict(\n                            required=False,\n                            type='str',\n                        ),\n                        context_id=dict(\n                            required=False,\n                            type='str',\n                        ),\n                        id=dict(\n                            required=False,\n                            type='str',\n                        ),\n                        traffic_tag=dict(\n                            required=False,\n                            type='int'\n                        ),\n                        type=dict(\n                            required=False,\n                            type='str',\n                            choices=['PARENT', 'CHILD', 'INDEPENDENT']\n                        )\n                    )\n                ),\n                extra_configs=dict(\n                    required=False,\n                    type='list',\n                    elements='dict',\n                    options=dict(\n                        config_pair=dict(\n                            required=True,\n                            type='dict',\n                            options=dict(\n                                key=dict(\n                                    required=True,\n                                    type='str'\n                                ),\n                                value=dict(\n                                    required=True,\n                                    type='str'\n                                )\n                            )\n                        ),\n                    )\n                ),\n                ignored_address_bindings=dict(\n                    required=False,\n                    type='list',\n                    elements='dict',\n                    options=dict(\n                        ip_address=dict(\n                            required=False,\n                            type='str'\n                        ),\n                        mac_address=dict(\n                            required=False,\n                            type='str'\n                        ),\n                        vlan_id=dict(\n                            required=False,\n                            type='int'\n                        )\n                    )\n                ),\n                init_state=dict(\n                    type='str',\n                    default='UNBLOCKED_VLAN',\n                    choices=['UNBLOCKED_VLAN']\n                )\n            )\n            return segment_port_arg_spec\n\n        @staticmethod\n        def get_resource_base_url(parent_info):\n            segment_id = parent_info.get(\"segment_id\", 'default')\n            return SEGMENT_PORT_URL.format(segment_id)\n\n\nif __name__ == '__main__':\n    segment = NSXTSegment()\n    segment.realize()\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_tier0.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\nmodule: nsxt_policy_tier0\nshort_description: 'Create/Update/Delete a Tier-0 and associated resources'\ndescription: Creates/Updates/Deletes a Tier-0 resource using the Policy API.\n             Assocaited resources include 'Tier-0 Locale Service' and\n             'Tier-0 Interface'. 'Tier-0 Locale Service' and 'Tier-0 Interface'\n             attributes must be prepended with 't0ls' and 't0iface'\n             respectively.\nversion_added: '2.8'\nauthor: 'Gautam Verma'\nextends_documentation_fragment:\n    - vmware.ansible_for_nsxt.vmware_nsxt\noptions:\n    id:\n        description: Tier-0 ID\n        required: false\n        type: str\n    description:\n        description: Tier-0 description\n        type: str\n    default_rule_logging:\n        description: Enable logging for whitelisted rule.\n                     Indicates if logging should be enabled for the default\n                     whitelisting rule.\n        default: false\n    ha_mode:\n        description: High-availability Mode for Tier-0\n        choices:\n            - 'ACTIVE_STANDBY'\n            - 'ACTIVE_ACTIVE'\n        default: 'ACTIVE_ACTIVE'\n        type: str\n    disable_firewall:\n        description: Disable or enable gateway fiewall.\n        default: False\n        type: bool\n    failover_mode:\n        description: Determines the behavior when a Tier-0 instance in\n                     ACTIVE-STANDBY high-availability mode restarts\n                     after a failure. If set to PREEMPTIVE, the preferred node\n                     will take over, even if it causes\n                     another failure. If set to NON_PREEMPTIVE, then\n                     the instance that restarted will remain secondary.\n                     This property must not be populated unless the\n                     ha_mode property is set to ACTIVE_STANDBY.\n        choices:\n            - 'NON_PREEMPTIVE'\n            - 'PREEMPTIVE'\n        default: 'NON_PREEMPTIVE'\n        type: str\n    force_whitelisting:\n        description: Flag to add whitelisting FW rule during\n                     realization.\n        default: False\n        type: bool\n    internal_transit_subnets:\n        description: Internal transit subnets in CIDR format.\n                     Specify subnets that are used to assign addresses\n                     to logical links connecting service routers and\n                     distributed routers. Only IPv4 addresses are\n                     supported. When not specified, subnet 169.254.0.0/\n                     24 is assigned by default in ACTIVE_ACTIVE HA mode\n                     or 169.254.0.0/28 in ACTIVE_STANDBY mode.\n        default: False\n        type: list\n    intersite_config:\n        description: Inter site routing configuration when the gateway is\n                     streched.\n        type: dict\n        suboptions:\n            fallback_sites:\n                description: Fallback site to be used as new primary\n                             site on current primary site failure.\n                             Disaster recovery must be initiated via\n                             API/UI. Fallback site configuration is\n                             supported only for T0 gateway. T1 gateway\n                             will follow T0 gateway's primary site\n                             during disaster recovery\n                type: list\n            intersite_transit_subnet:\n                description:\n                    - Transit subnet in CIDR format\n                    - IPv4 subnet for inter-site transit segment\n                      connecting service routers across sites for\n                      stretched gateway. For IPv6 link local subnet is\n                      auto configured\n                type: str\n                default: \"169.254.32.0/20\"\n            last_admin_active_epoch:\n                description:\n                    - Epoch of last time admin changing active\n                      LocaleServices\n                    - Epoch(in seconds) is auto updated based on\n                      system current timestamp when primary locale\n                      service is updated. It is used for resolving\n                      conflict during site failover. If system clock\n                      not in sync then User can optionally override\n                      this. New value must be higher than the current\n                      value.\n                type: int\n            primary_site_path:\n                description:\n                    - Primary egress site for gateway.\n                    - Primary egress site for gateway. T0/T1 gateway in\n                      Active/Standby mode supports stateful services on primary\n                      site. In this mode primary site must be set if gateway is\n                      stretched to more than one site. For T0 gateway in\n                      Active/Active primary site is optional field. If set then\n                      secondary site prefers routes learned from primary over\n                      locally learned routes. This field is not applicable for\n                      T1 gateway with no services\n                type: str\n    ipv6_ndra_profile_id:\n        description: IPv6 NDRA profile configuration on Tier0.\n                     Either or both NDRA and/or DAD profiles can be\n                     configured. Related attribute ipv6_dad_profile_id.\n        type: str\n    ipv6_ndra_profile_display_name:\n        description: Same as ipv6_ndra_profile_id. Either one can be specified.\n                     If both are specified, ipv6_ndra_profile_id takes\n                     precedence.\n        type: str\n    ipv6_dad_profile_id:\n        description: IPv6 DRA profile configuration on Tier0.\n                     Either or both NDRA and/or DAD profiles can be\n                     configured. Related attribute ipv6_ndra_profile_id.\n        type: str\n    ipv6_dad_profile_display_name:\n        description: Same as ipv6_dad_profile_id. Either one can be specified.\n                     If both are specified, ipv6_dad_profile_id takes\n                     precedence.\n        type: str\n    rd_admin_field:\n        description:\n            - Route distinguisher administrator address\n            - If you are using EVPN service, then route distinguisher\n              administrator address should be defined if you need auto\n              generation of route distinguisher on your VRF configuration\n        type: str\n    transit_subnets:\n        description: Transit subnets in CIDR format.\n                     Specify transit subnets that are used to assign\n                     addresses to logical links connecting tier-0 and\n                     tier-1s. Both IPv4 and IPv6 addresses are\n                     supported.\n                     When not specified, subnet 100.64.0.0/16 is\n                     configured by default.\n        type: list\n    dhcp_config_id:\n        description: DHCP configuration for Segments connected to\n                     Tier-0. DHCP service is configured in relay mode.\n        type: str\n    dhcp_config_display_name:\n        description: Same as dhcp_config_id. Either one can be specified.\n                     If both are specified, dhcp_config_id takes precedence.\n        type: str\n    vrf_config:\n        type: dict\n        description: VRF config, required for VRF Tier0\n        suboptions:\n            description:\n                description: Description of this resource\n                type: str\n            display_name:\n                description:\n                    - Identifier to use when displaying entity in logs or GUI\n                    - Defaults to id if not set\n                    - Error if both not specified\n                type: str\n            evpn_transit_vni:\n                description:\n                    - L3 VNI associated with the VRF for overlay traffic.\n                    - VNI must be unique and belong to configured VNI pool.\n                type: int\n            id:\n                description:\n                    - Unique identifier of this resource\n                    - Defaults to display_name if not set\n                    - Error if both not specified\n                type: str\n            route_distinguisher:\n                description: Route distinguisher. 'ASN:<>' or 'IPAddress:<>'.\n                type: str\n            route_targets:\n                description: Route targets\n                type: list\n                element: dict\n                suboptions:\n                    description:\n                        description: Description of this resource\n                        type: str\n                    display_name:\n                        description:\n                            - Identifier to use when displaying entity in logs\n                              or GUI\n                            - Defaults to id if not set\n                            - Error if both not specified\n                        type: str\n                    export_route_targets:\n                        description: Export route targets. 'ASN:' or\n                                     'IPAddress:<>'\n                        type: list\n                        element: str\n                    id:\n                        description:\n                            - Unique identifier of this resource\n                            - Defaults to display_name if not set\n                            - Error if both not specified\n                        type: str\n                    import_route_targets:\n                        description: Import route targets. 'ASN:' or\n                                     'IPAddress:<>'\n                        type: list\n                        element: str\n                    tags:\n                        description: Opaque identifiers meaningful to the API\n                                     user\n                        type: list\n                        element: dict\n                        suboptions:\n                            scope:\n                                description: Tag scope\n                                type: str\n                            tag:\n                                description: Tag value\n                                type: str\n            tags:\n                description: Opaque identifiers meaningful to the API user\n                type: list\n                element: dict\n                suboptions:\n                    scope:\n                        description: Tag scope\n                        type: str\n                    tag:\n                        description: Tag value\n                        type: str\n            tier0_display_name:\n                description: Default tier0 display name. Cannot be modified\n                             after realization. Either this or tier0_id must\n                             be specified\n                type: str\n            tier0_id:\n                description: Default tier0 id. Cannot be modified after\n                             realization. Either this or tier0_id must\n                             be specified\n                type: str\n    static_routes:\n        type: list\n        element: dict\n        description: This is a list of Static Routes that need to be created,\n                     updated, or deleted\n        suboptions:\n            id:\n                description: Tier-0 Static Route ID.\n                required: false\n                type: str\n            display_name:\n                description:\n                    - Tier-0 Static Route display name.\n                    - Either this or id must be specified. If both are\n                      specified, id takes precedence.\n                required: false\n                type: str\n            description:\n                description:\n                    - Tier-0 Static Route description.\n                type: str\n            state:\n                description:\n                    - State can be either 'present' or 'absent'. 'present' is\n                      used to create or update resource. 'absent' is used to\n                      delete resource.\n                    - Must be specified in order to modify the resource\n                choices:\n                    - present\n                    - absent\n            network:\n                description: Network address in CIDR format\n                required: true\n                type: str\n            next_hops:\n                description: Next hop routes for network\n                type: list\n                elements: dict\n                suboptions:\n                    admin_distance:\n                        description: Cost associated with next hop route\n                        type: int\n                        default: 1\n                ip_address:\n                    description: Next hop gateway IP address\n                    type: str\n                scope:\n                    description:\n                        - Interface path associated with current route\n                        - For example, specify a policy path referencing the\n                          IPSec VPN Session\n                    type: list\n            tags:\n                description: Opaque identifiers meaningful to the API user\n                type: dict\n                suboptions:\n                    scope:\n                        description: Tag scope.\n                        required: true\n                        type: str\n                    tag:\n                        description: Tag value.\n                        required: true\n                        type: str\n            achieve_subresource_state_if_del_parent:\n                type: bool\n                default: false\n                description:\n                    - Can be used to achieve the state of subresources even if\n                      the parent(base) resource's state is absent.\n                    - Can be specified for each subresource.\n            do_wait_till_create:\n                type: bool\n                default: false\n                description:\n                    - Can be used to wait for the realization of subresource\n                      before the request to create the next resource is sent to\n                      the Manager\n    bfd_peers:\n        type: list\n        element: dict\n        description: This is a list of BFD Peers that need to be created,\n                     updated, or deleted\n        suboptions:\n            id:\n                description: Tier-0 BFD Peer ID.\n                required: false\n                type: str\n            display_name:\n                description:\n                    - Tier-0 BFD Peer display name.\n                    - Either this or id must be specified. If both are\n                      specified, id takes precedence.\n                required: false\n                type: str\n            description:\n                description:\n                    - Tier-0 BFD Peer description. config\n                type: str\n            state:\n                description:\n                    - State can be either 'present' or 'absent'. 'present' is\n                      used to create or update resource. 'absent' is used to\n                      delete resource.\n                    - Must be specified in order to modify the resource\n                choices:\n                    - present\n                    - absent\n            bfd_profile_id:\n                description:\n                    - The associated BFD Profile ID\n                    - Either this or bfd_profile_display_name must be specified\n                    - BFD Profile is not supported for IPv6 networks.\n                type: str\n            bfd_profile_display_name:\n                description:\n                    - The associated BFD Profile display name\n                    - Either this or bfd_profile_id must be specified\n                    - BFD Profile is not supported for IPv6 networks.\n                type: str\n            enabled:\n                description: Flag to enable BFD peer.\n                type: list\n                elements: dict\n                suboptions:\n                    admin_distance:\n                        description: Cost associated with next hop route\n                        type: int\n                        default: 1\n                ip_address:\n                    description: Next hop gateway IP address\n                    type: str\n                scope:\n                    description:\n                        - Interface path associated with current route\n                        - For example, specify a policy path referencing the\n                          IPSec VPN Session\n                    type: list\n            tags:\n                description: Opaque identifiers meaningful to the API user\n                type: dict\n                suboptions:\n                    scope:\n                        description: Tag scope.\n                        required: true\n                        type: str\n                    tag:\n                        description: Tag value.\n                        required: true\n                        type: str\n    locale_services:\n        type: list\n        element: dict\n        description: This is a list of Locale Services that need to be created,\n                     updated, or deleted\n        suboptions:\n            id:\n                description: Tier-0 Locale Service ID.\n                required: false\n                type: str\n            display_name:\n                description:\n                    - Tier-0 Locale Service display name.\n                    - Either this or id must be specified. If both are\n                      specified, id takes precedence\n                required: false\n                type: str\n            description:\n                description:\n                    - Tier-0 Locale Service  description.\n                type: str\n            state:\n                description:\n                    - State can be either 'present' or 'absent'. 'present' is\n                      used to create or update resource. 'absent' is used to\n                      delete resource\n                    - Required if id is specified.\n                choices:\n                    - present\n                    - absent\n            tags:\n                description: Opaque identifiers meaningful to the API user\n                type: dict\n                suboptions:\n                    scope:\n                        description: Tag scope.\n                        required: true\n                        type: str\n                    tag:\n                        description: Tag value.\n                        required: true\n                        type: str\n            create_or_update_subresource_first:\n                type: bool\n                default: false\n                description:\n                    - Can be used to create subresources first.\n                    - Can be specified for each subresource.\n            delete_subresource_first:\n                type: bool\n                default: true\n                description:\n                    - Can be used to delete subresources first.\n                    - Can be specified for each subresource.\n            achieve_subresource_state_if_del_parent:\n                type: bool\n                default: false\n                description:\n                    - Can be used to achieve the state of subresources even if\n                      the parent(base) resource's state is absent.\n                    - Can be specified for each subresource.\n            do_wait_till_create:\n                type: bool\n                default: false\n                description:\n                    - Can be used to wait for the realization of subresource\n                      before the request to create the next resource is sent to\n                      the Manager.\n                    - Can be specified for each subresource.\n            edge_cluster_info:\n                description: Used to create path to edge cluster. Auto-assigned\n                            if associated enforcement-point has only one edge\n                            cluster.\n                type: dict\n                suboptions:\n                    site_id:\n                        description: site_id where edge cluster is located\n                        default: default\n                        type: str\n                    enforcementpoint_id:\n                        description: enforcementpoint_id where edge cluster is\n                                    located\n                        default: default\n                        type: str\n                    edge_cluster_id:\n                        description: ID of the edge cluster\n                        type: str\n                    edge_cluster_display_name:\n                        description:\n                            - display name of the edge cluster.\n                            - Either this or edge_cluster_id must be specified.\n                              If both are specified, edge_cluster_id takes\n                              precedence\n                        type: str\n            preferred_edge_nodes_info:\n                description: Used to create paths to edge nodes. Specified edge\n                            is used as preferred edge cluster member when\n                            failover mode is set to PREEMPTIVE, not\n                            applicable otherwise.\n                type: list\n                suboptions:\n                    site_id:\n                        description: site_id where edge node is located\n                        default: default\n                        type: str\n                    enforcementpoint_id:\n                        description: enforcementpoint_id where edge node is\n                                    located\n                        default: default\n                        type: str\n                    edge_cluster_id:\n                        description: edge_cluster_id where edge node is\n                                    located\n                        type: str\n                    edge_cluster_display_name:\n                        description:\n                            - display name of the edge cluster.\n                            - either this or edge_cluster_id must be specified.\n                              If both are specified, edge_cluster_id takes\n                              precedence\n                        type: str\n                    edge_node_id:\n                        description: ID of the edge node\n                        type: str\n                    edge_node_display_name:\n                        description:\n                            - Display name of the edge node.\n                            - either this or edge_node_id must be specified. If\n                              both are specified, edge_node_id takes precedence\n                        type: str\n            route_redistribution_types:\n                description:\n                    - Enable redistribution of different types of routes on\n                      Tier-0.\n                    - This property is only valid for locale-service under\n                      Tier-0.\n                    - This property is deprecated, please use\n                      \"route_redistribution_config\" property to configure\n                      redistribution rules.\n                type: list\n                choices:\n                    - TIER0_STATIC - Redistribute user added\n                        static routes.\n                    - TIER0_CONNECTED - Redistribute all\n                        subnets configured on Interfaces and\n                        routes related to TIER0_ROUTER_LINK,\n                        TIER0_SEGMENT, TIER0_DNS_FORWARDER_IP,\n                        TIER0_IPSEC_LOCAL_IP, TIER0_NAT types.\n                    - TIER1_STATIC - Redistribute all subnets\n                        and static routes advertised by Tier-1s.\n                    - TIER0_EXTERNAL_INTERFACE - Redistribute\n                        external interface subnets on Tier-0.\n                    - TIER0_LOOPBACK_INTERFACE - Redistribute\n                        loopback interface subnets on Tier-0.\n                    - TIER0_SEGMENT - Redistribute subnets\n                        configured on Segments connected to\n                        Tier-0.\n                    - TIER0_ROUTER_LINK - Redistribute router\n                        link port subnets on Tier-0.\n                    - TIER0_SERVICE_INTERFACE - Redistribute\n                        Tier0 service interface subnets.\n                    - TIER0_DNS_FORWARDER_IP - Redistribute DNS\n                        forwarder subnets.\n                    - TIER0_IPSEC_LOCAL_IP - Redistribute IPSec\n                        subnets.\n                    - TIER0_NAT - Redistribute NAT IPs owned by\n                        Tier-0.\n                    - TIER0_EVPN_TEP_IP - Redistribute EVPN\n                        local endpoint subnets on Tier-0.\n                    - TIER1_NAT - Redistribute NAT IPs\n                        advertised by Tier-1 instances.\n                    - TIER1_LB_VIP - Redistribute LB VIP IPs\n                        advertised by Tier-1 instances.\n                    - TIER1_LB_SNAT - Redistribute LB SNAT IPs\n                        advertised by Tier-1 instances.\n                    - TIER1_DNS_FORWARDER_IP - Redistribute DNS\n                        forwarder subnets on Tier-1 instances.\n                    - TIER1_CONNECTED - Redistribute all\n                        subnets configured on Segments and\n                        Service Interfaces.\n                    - TIER1_SERVICE_INTERFACE - Redistribute\n                        Tier1 service interface subnets.\n                    - TIER1_SEGMENT - Redistribute subnets\n                        configured on Segments connected to\n                        Tier1.\n                    - TIER1_IPSEC_LOCAL_ENDPOINT - Redistribute\n                        IPSec VPN local-endpoint subnets\n                        advertised by TIER1.\n            route_redistribution_config:\n                description: Configure all route redistribution properties like\n                             enable/disable redistributon, redistribution rule\n                             and so on.\n                type: dict\n                suboptions:\n                    bgp_enabled:\n                        description: Flag to enable route redistribution.\n                        type: bool\n                        default: false\n                    redistribution_rules:\n                        description: List of redistribution rules.\n                        type: list\n                        elements: dict\n                        suboptions:\n                            name:\n                                description: Rule name\n                                type: str\n                            route_map_path:\n                                description: Route map to be associated with\n                                             the redistribution rule\n                                type: str\n                            route_redistribution_types:\n                                description: Tier-0 route redistribution types\n                                choices:\n                                    - TIER0_STATIC - Redistribute user added\n                                      static routes.\n                                    - TIER0_CONNECTED - Redistribute all\n                                      subnets configured on Interfaces and\n                                      routes related to TIER0_ROUTER_LINK,\n                                      TIER0_SEGMENT, TIER0_DNS_FORWARDER_IP,\n                                      TIER0_IPSEC_LOCAL_IP, TIER0_NAT types.\n                                    - TIER1_STATIC - Redistribute all subnets\n                                      and static routes advertised by Tier-1s.\n                                    - TIER0_EXTERNAL_INTERFACE - Redistribute\n                                      external interface subnets on Tier-0.\n                                    - TIER0_LOOPBACK_INTERFACE - Redistribute\n                                      loopback interface subnets on Tier-0.\n                                    - TIER0_SEGMENT - Redistribute subnets\n                                      configured on Segments connected to\n                                      Tier-0.\n                                    - TIER0_ROUTER_LINK - Redistribute router\n                                      link port subnets on Tier-0.\n                                    - TIER0_SERVICE_INTERFACE - Redistribute\n                                      Tier0 service interface subnets.\n                                    - TIER0_DNS_FORWARDER_IP - Redistribute DNS\n                                      forwarder subnets.\n                                    - TIER0_IPSEC_LOCAL_IP - Redistribute IPSec\n                                      subnets.\n                                    - TIER0_NAT - Redistribute NAT IPs owned by\n                                      Tier-0.\n                                    - TIER0_EVPN_TEP_IP - Redistribute EVPN\n                                      local endpoint subnets on Tier-0.\n                                    - TIER1_NAT - Redistribute NAT IPs\n                                      advertised by Tier-1 instances.\n                                    - TIER1_LB_VIP - Redistribute LB VIP IPs\n                                      advertised by Tier-1 instances.\n                                    - TIER1_LB_SNAT - Redistribute LB SNAT IPs\n                                      advertised by Tier-1 instances.\n                                    - TIER1_DNS_FORWARDER_IP - Redistribute DNS\n                                      forwarder subnets on Tier-1 instances.\n                                    - TIER1_CONNECTED - Redistribute all\n                                      subnets configured on Segments and\n                                      Service Interfaces.\n                                    - TIER1_SERVICE_INTERFACE - Redistribute\n                                      Tier1 service interface subnets.\n                                    - TIER1_SEGMENT - Redistribute subnets\n                                      configured on Segments connected to\n                                      Tier1.\n                                    - TIER1_IPSEC_LOCAL_ENDPOINT - Redistribute\n                                      IPSec VPN local-endpoint subnets\n                                      advertised by TIER1.\n                                type: list\n            ha_vip_configs:\n                type: list\n                elements: dict\n                description:\n                    - Array of HA VIP Config.\n                    - This configuration can be defined only for Active-Standby\n                      Tier0 gateway to provide redundancy. For mulitple\n                      external interfaces, multiple HA VIP configs must be\n                      defined and each config will pair exactly two external\n                      interfaces. The VIP will move and will always be owned by\n                      the Active node. When this property is configured,\n                      configuration of dynamic-routing is not allowed.\n                suboptions:\n                    enabled:\n                        description: Flag to enable this HA VIP config.\n                        default: true\n                        type: bool\n                    external_interface_paths:\n                        description:\n                            - Policy paths to Tier0 external interfaces for\n                              providing redundancy\n                            - Policy paths to Tier0 external interfaces which\n                              are to be paired to provide redundancy. Floating\n                              IP will be owned by one of these interfaces\n                              depending upon which edge node is Active.\n                        type: list\n                    vip_subnets:\n                        description:\n                            - VIP floating IP address subnets\n                            - Array of IP address subnets which will be used as\n                              floating IP addresses.\n                        type: list\n                        suboptions:\n                            ip_addresses:\n                                description: IP addresses assigned to interface\n                                type: list\n                                required: true\n                            prefix_len:\n                                description: Subnet prefix length\n                                type: int\n                                required: true\n            BGP:\n                description: Specify the BGP spec in this section\n                type: dict\n                suboptions:\n                    ecmp:\n                        description: Flag to enable ECMP.\n                        type: bool\n                        required: False\n                        default: True\n                    enabled:\n                        description: Flag to enable BGP configuration.\n                                     Disabling will stop feature and BGP\n                                     peering.\n                        type: bool\n                        default: True\n                    graceful_restart_config:\n                        description: Configuration field to hold BGP Restart\n                                     mode and timer.\n                        type: dict\n                        required: False\n                        suboptions:\n                            mode:\n                                description:\n                                    - BGP Graceful Restart Configuration Mode\n                                    - If mode is DISABLE, then graceful restart\n                                      and helper modes are disabled.\n                                    - If mode is GR_AND_HELPER, then both\n                                      graceful restart and helper modes are\n                                      enabled.\n                                    - If mode is HELPER_ONLY, then helper mode\n                                      is enabled. HELPER_ONLY mode is the\n                                      ability for a BGP speaker to indicate its\n                                      ability to preserve forwarding state\n                                      during BGP restart.\n                                    - GRACEFUL_RESTART mode is the ability of a\n                                      BGP speaker to advertise its restart to\n                                      its peers.\n                                type: str\n                                required: False\n                                default: 'HELPER_ONLY'\n                                choices:\n                                    - DISABLE\n                                    - GR_AND_HELPER\n                                    - HELPER_ONLY\n                            timer:\n                                description: BGP Graceful Restart Timer\n                                type: dict\n                                required: False\n                                suboptions:\n                                    restart_timer:\n                                        description:\n                                            - BGP Graceful Restart Timer\n                                            - Maximum time taken (in seconds)\n                                              for a BGP session to be\n                                              established after a restart. This\n                                              can be used to speed up routing\n                                              convergence by its peer in case\n                                              the BGP speaker does not come\n                                              back up after a restart. If the\n                                              session is not re-established\n                                              within this timer, the receiving\n                                              speaker will delete all the stale\n                                              routes from that peer. Min 1 and\n                                              Max 3600\n                                        type: int\n                                        default: 180\n                                    stale_route_timer:\n                                        description:\n                                            - BGP Stale Route Timer\n                                            - Maximum time (in seconds) before\n                                              stale routes are removed from the\n                                              RIB (Routing Information Base)\n                                              when BGP restarts. Min 1 and Max\n                                              3600\n                                        type: int\n                                        default: 600\n                    inter_sr_ibgp:\n                        description: Flag to enable inter SR IBGP\n                                     configuration. When not specified, inter\n                                     SR IBGP is automatically enabled if Tier-0\n                                     is created in ACTIVE_ACTIVE ha_mode.\n                        type: bool\n                        required: False\n                    local_as_num:\n                        description:\n                            - BGP AS number in ASPLAIN/ASDOT Format.\n                            - Specify BGP AS number for Tier-0 to advertize to\n                              BGP peers. AS number can be specified in ASPLAIN\n                              (e.g., \"65546\") or ASDOT (e.g., \"1.10\") format.\n                              Empty string disables BGP feature.\n                        type: str\n                        required: True\n                    multipath_relax:\n                        description: Flag to enable BGP multipath relax option.\n                        type: bool\n                        default: True\n                    route_aggregations:\n                        description: List of routes to be aggregated\n                        type: dict\n                        required: False\n                        suboptions:\n                            prefix:\n                                description: CIDR of aggregate address\n                                type: str\n                                required: True\n                            summary_only:\n                                description:\n                                    - Send only summarized route.\n                                    - Summarization reduces number of routes\n                                      advertised by representing multiple\n                                      related routes with prefix property\n                                type: bool\n                                default: True\n                    neighbors:\n                        description: Specify the BGP neighbors in this section\n                                     that need to be created, updated, or\n                                     deleted\n                        type: list\n                        element: dict\n                        suboptions:\n                            allow_as_in:\n                                description: Flag to enable allowas_in option\n                                             for BGP neighbor\n                                type: bool\n                                default: False\n                            bfd:\n                                description:\n                                    - BFD configuration for failure detection\n                                    - BFD is enabled with default values when\n                                      not configured\n                                type: dict\n                                required: False\n                                suboptions:\n                                    enabled:\n                                        description: Flag to enable BFD\n                                                     cofiguration\n                                        type: bool\n                                        required: False\n                                    interval:\n                                        description: Time interval between\n                                                     heartbeat packets in\n                                                     milliseconds. Min 300 and\n                                                     Max 60000\n                                        type: int\n                                        default: 1000\n                                    multiple:\n                                        description:\n                                            - Declare dead multiple.\n                                            - Number of times heartbeat packet\n                                              is missed before BFD declares the\n                                              neighbor is down.\n                                              Min 2 and Max 16\n                                        type: int\n                                        default: 3\n                            graceful_restart_mode:\n                                description:\n                                    - BGP Graceful Restart Configuration Mode\n                                    - If mode is DISABLE, then graceful restart\n                                      and helper modes are disabled.\n                                    - If mode is GR_AND_HELPER, then both\n                                      graceful restart and helper modes are\n                                      enabled.\n                                    - If mode is HELPER_ONLY, then helper mode\n                                      is enabled. HELPER_ONLY mode is the\n                                      ability for a BGP speaker to indicate its\n                                      ability to preserve forwarding state\n                                      during BGP restart.\n                                    - GRACEFUL_RESTART mode is the ability of a\n                                      BGP speaker to advertise its restart to\n                                      its peers.\n                                type: str\n                                choices:\n                                    - DISABLE\n                                    - GR_AND_HELPER\n                                    - HELPER_ONLY\n                            hold_down_time:\n                                description: Wait time in seconds before\n                                             declaring peer dead. Min 1 and Max\n                                             65535\n                                type: int\n                                default: 180\n                            keep_alive_time:\n                                description: Interval between keep alive\n                                             messages sent to peer. Min 1 and\n                                             Max 65535.\n                                type: int\n                                default: 60\n                            maximum_hop_limit:\n                                description: Maximum number of hops allowed to\n                                             reach BGP neighbor. Min 1 and Max\n                                             255\n                                type: int\n                                default: 1\n                            address:\n                                description: Neighbor IP Address\n                                type: str\n                                required: True\n                            password:\n                                description: Password for BGP Neighbor\n                                             authentication. Empty string (\"\")\n                                             clears existing password.\n                                type: str\n                                required: False\n                            remote_as_num:\n                                description: 4 Byte ASN of the neighbor in\n                                             ASPLAIN Format\n                                type: str\n                                required: True\n                            route_filtering:\n                                description: Enable address families and route\n                                             filtering in each direction\n                                type: list\n                                elements: dict\n                                required: False\n                                suboptions:\n                                    address_family:\n                                        description: Address family type\n                                        type: str\n                                        required: False\n                                        choices:\n                                            - 'IPV4'\n                                            - 'IPV6'\n                                            - 'VPN'\n                                    enabled:\n                                        description: Flag to enable address\n                                                     family\n                                        type: bool\n                                        default: True\n                                    in_route_filters:\n                                        description:\n                                            - Prefix-list or route map path for\n                                              IN direction\n                                            - Specify path of prefix-list or\n                                              route map to filter routes for IN\n                                              direction.\n                                        type: list\n                                        required: False\n                                    out_route_filters:\n                                        description:\n                                            - Prefix-list or route map path for\n                                              OUT direction\n                                            - Specify path of prefix-list or\n                                              route map to filter routes\n                                              for OUT direction. When not\n                                              specified, a built-in\n                                              prefix-list named\n                                              'prefixlist-out-default' is\n                                              automatically applied.\n                                        type: list\n                                        required: False\n                            source_addresses:\n                                description:\n                                    - Source IP Addresses for BGP peering\n                                    - Source addresses should belong to Tier0\n                                      external or loopback interface IP\n                                      Addresses. BGP peering is formed from all\n                                      these addresses. This property is\n                                      mandatory when maximum_hop_limit is\n                                      greater than 1.\n                                type: list\n                                required: False\n            interfaces:\n                type: list\n                element: dict\n                description: Specify the interfaces associated with the Gateway\n                             in this section that need to be created, updated,\n                             or deleted\n                suboptions:\n                    id:\n                        description: Tier-0 Interface ID\n                        type: str\n                    display_name:\n                        description:\n                            - Tier-0 Interface display name\n                            - Either this or id must be specified. If both are\n                              specified, id takes precedence.\n                        required: false\n                        type: str\n                    description:\n                        description: Tier-0 Interface  description\n                        type: str\n                    state:\n                        description:\n                            - State can be either 'present' or 'absent'.\n                              'present' is used to create or update resource.\n                              'absent' is used to delete resource.\n                            - Required if I(segp_id != null)\n                        choices:\n                            - present\n                            - absent\n                    tags:\n                        description: Opaque identifiers meaningful to the API\n                                     user\n                        type: dict\n                        suboptions:\n                            scope:\n                                description: Tag scope.\n                                required: true\n                                type: str\n                            tag:\n                                description: Tag value.\n                                required: true\n                                type: str\n                    access_vlan_id:\n                        description: Vlan id\n                        type: int\n                    ipv6_ndra_profile_display_name:\n                        description: Same as ipv6_ndra_profile_id. Either one\n                                     should be specified.\n                        type: str\n                    ipv6_ndra_profile_id:\n                        description: Configuration IPv6 NDRA profile. Only one\n                                     NDRA profile can be configured.\n                        type: str\n                    mtu:\n                        description:\n                            - MTU size\n                            - Maximum transmission unit (MTU) specifies the\n                              size of the largest packet that a network\n                              protocol can transmit.\n                        type: int\n                    multicast:\n                        description: Multicast PIM configuration\n                        type: dict\n                        suboptions:\n                            enabled:\n                                description: enable/disable PIM configuration\n                                type: bool\n                                default: False\n                    urpf_mode:\n                        description: Unicast Reverse Path Forwarding mode\n                        type: str\n                        choices:\n                            - NONE\n                            - STRICT\n                        default: STRICT\n                    create_or_update_subresource_first:\n                        type: bool\n                        default: false\n                        description:\n                            - Can be used to create subresources first.\n                            - Can be specified for each subresource.\n                    delete_subresource_first:\n                        type: bool\n                        default: true\n                        description:\n                            - Can be used to delete subresources first.\n                            - Can be specified for each subresource.\n                    achieve_subresource_state_if_del_parent:\n                        type: bool\n                        default: false\n                        description:\n                            - Can be used to achieve the state of subresources\n                              even if the parent(base) resource's state is\n                              absent.\n                            - Can be specified for each subresource.\n                    do_wait_till_create:\n                        type: bool\n                        default: false\n                        description:\n                            - Can be used to wait for the realization of\n                              subresource before the request to create the next\n                              resource is sent to the Manager.\n                            - Can be specified for each subresource.\n                    segment_id:\n                        description: Specify Segment to which this interface is\n                                     connected to. Required if id is specified.\n                        type: str\n                    segment_display_name:\n                        description:\n                            - Same as segment_id\n                            - Either this or segment_id must be specified. If\n                              both are specified, segment_id takes precedence.\n                        type: str\n                    type:\n                        description: Interface type\n                        choices:\n                            - \"EXTERNAL\"\n                            - \"LOOPBACK\"\n                            - \"SERVICE\"\n                        default: \"EXTERNAL\"\n                        type: str\n                    edge_node_info:\n                        description:\n                            - Info to create policy path to edge node to\n                              handle externalconnectivity.\n                            - Required if interface type is EXTERNAL and\n                              I(id != null)\n                        type: dict\n                        suboptions:\n                            site_id:\n                                description: site_id where edge node is located\n                                default: default\n                                type: str\n                            enforcementpoint_id:\n                                description: enforcementpoint_id where edge\n                                             node is located\n                                default: default\n                                type: str\n                            edge_cluster_id:\n                                description: edge_cluster_id where edge node is\n                                             located\n                                type: str\n                            edge_cluster_display_name:\n                                description:\n                                    - display name of the edge cluster.\n                                    - either this or edge_cluster_id must be\n                                      specified. If both are specified,\n                                      edge_cluster_id takes precedence\n                                type: str\n                            edge_node_id:\n                                description: ID of the edge node\n                                type: str\n                            edge_node_display_name:\n                                description:\n                                    - Display name of the edge node.\n                                    - either this or edge_node_id must be\n                                      specified. If both are specified,\n                                      edge_node_id takes precedence.\n                                type: str\n                    subnets:\n                        description:\n                            - IP address and subnet specification for interface\n                            - Specify IP address and network prefix for\n                              interface.\n                            - Required if I(id != null).\n                        type: list\n'''\n\nEXAMPLES = '''\n- name: create Tier0\n  nsxt_policy_tier0:\n    hostname: \"10.10.10.10\"\n    nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n    nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n    validate_certs: False\n    display_name: test-tier0-1\n    state: present\n    ha_mode: \"ACTIVE_STANDBY\"\n    failover_mode: \"PREEMPTIVE\"\n    disable_firewall: True\n    force_whitelisting: True\n    rd_admin_field: \"122.34.12.124\"\n    tags:\n      - scope: \"a\"\n        tag: \"b\"\n    static_routes:\n      - state: present\n        display_name: test-sr\n        network: '12.12.12.0/24'\n        next_hops:\n          - ip_address: \"192.165.1.4\"\n    bfd_peers:\n      - state: present\n        display_name: test-peer-1\n        peer_address: \"192.100.100.5\"\n        bfd_profile_id: test-bfd-config\n    locale_services:\n      - state: present\n        id: \"test-t0ls\"\n        route_redistribution_config:\n          redistribution_rules:\n            - name: abc\n              route_redistribution_types: [\"TIER0_STATIC\", \"TIER0_NAT\"]\n        edge_cluster_info:\n          edge_cluster_id: \"7ef91a10-c780-4f48-a279-a5662db4ffa3\"\n        preferred_edge_nodes_info:\n          - edge_cluster_id: \"7ef91a10-c780-4f48-a279-a5662db4ffa3\"\n            edge_node_id: \"e10c42dc-db27-11e9-8cd0-000c291af7ee\"\n        BGP:\n          state: present\n          local_as_num: '1211'\n          inter_sr_ibgp: False\n          graceful_restart_config:\n          mode: \"GR_AND_HELPER\"\n          timer:\n            restart_timer: 12\n          route_aggregations:\n            - prefix: \"10.1.1.0/24\"\n            - prefix: \"11.1.0.0/24\"\n              summary_only: False\n          neighbors:\n            - display_name: neigh1\n              address: \"1.2.3.4\"\n              remote_as_num: \"12\"\n              state: present\n        interfaces:\n          - id: \"test-t0-t0ls-iface\"\n            display_name: \"test-t0-t0ls-iface\"\n            state: present\n            subnets:\n              - ip_addresses: [\"35.1.1.1\"]\n                prefix_len: 24\n            segment_id: \"test-seg-4\"\n            edge_node_info:\n              edge_cluster_id: \"7ef91a10-c780-4f48-a279-a5662db4ffa3\"\n              edge_node_id: \"e10c42dc-db27-11e9-8cd0-000c291af7ee\"\n            mtu: 1500\n            urpf_mode: \"NONE\"\n            multicast:\n              enabled: True\n            ipv6_ndra_profile_display_name: test\n    vrf_config:\n      display_name: my-vrf\n      id: my-vrf2\n      tier0_display_name: node-t0\n      tags:\n        - scope: scope-tag-1\n          tag: value-tag-1\n      route_distinguisher: 'ASN:4000'\n      evpn_transit_vni: 6000\n'''\n\nRETURN = '''# '''\n\n\nimport json\nimport time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible.module_utils._text import to_native\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_base_resource import NSXTBaseRealizableResource\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import (\n    TIER_0_URL, IPV6_DAD_PROFILE_URL, IPV6_NDRA_PROFILE_URL,\n    DHCP_RELAY_CONFIG_URL, EDGE_CLUSTER_URL, EDGE_NODE_URL, SEGMENT_URL,\n    TIER_0_STATIC_ROUTE_URL, TIER_0_LOCALE_SERVICE_URL,\n    TIER_0_LS_INTERFACE_URL, TIER_0_BGP_NEIGHBOR_URL, TIER_0_BFD_PEERS)\n\n\nclass NSXTTier0(NSXTBaseRealizableResource):\n    @staticmethod\n    def get_resource_spec():\n        tier0_arg_spec = {}\n        tier0_arg_spec.update(\n            default_rule_logging=dict(\n                required=False,\n                type='bool'\n            ),\n            ha_mode=dict(\n                required=False,\n                type='str',\n                default=\"ACTIVE_ACTIVE\",\n                choices=['ACTIVE_STANDBY', 'ACTIVE_ACTIVE']\n            ),\n            disable_firewall=dict(\n                required=False,\n                type='bool',\n                default=False\n            ),\n            failover_mode=dict(\n                required=False,\n                type='str',\n                default='NON_PREEMPTIVE',\n                choices=['NON_PREEMPTIVE', 'PREEMPTIVE']\n            ),\n            force_whitelisting=dict(\n                required=False,\n                type='bool',\n                default=False\n            ),\n            internal_transit_subnets=dict(\n                required=False,\n                type='list'\n            ),\n            intersite_config=dict(\n                required=False,\n                type='dict',\n                options=dict(\n                    fallback_sites=dict(\n                        required=False,\n                        type='list'\n                    ),\n                    intersite_transit_subnet=dict(\n                        default=\"169.254.32.0/20\",\n                        type='str'\n                    ),\n                    last_admin_active_epoch=dict(\n                        required=False,\n                        type='int'\n                    ),\n                    primary_site_path=dict(\n                        required=False,\n                        type='str'\n                    ),\n                )\n            ),\n            ipv6_ndra_profile_id=dict(\n                required=False,\n                type='str'\n            ),\n            ipv6_ndra_profile_display_name=dict(\n                required=False,\n                type='str'\n            ),\n            ipv6_dad_profile_id=dict(\n                required=False,\n                type='str'\n            ),\n            ipv6_dad_profile_display_name=dict(\n                required=False,\n                type='str'\n            ),\n            transit_subnets=dict(\n                required=False,\n                type='list'\n            ),\n            dhcp_config_id=dict(\n                required=False,\n                type='str'\n            ),\n            dhcp_config_display_name=dict(\n                required=False,\n                type='str'\n            ),\n            rd_admin_field=dict(\n                required=False,\n                type='str'\n            ),\n            vrf_config=dict(\n                required=False,\n                type='dict',\n                options=dict(\n                    # Note that only default site_id and\n                    # enforcementpoint_id are used\n                    description=dict(\n                        type='str',\n                        default=\"\"\n                    ),\n                    display_name=dict(\n                        type='str',\n                    ),\n                    evpn_transit_vni=dict(\n                        type='int'\n                    ),\n                    id=dict(\n                        type='str'\n                    ),\n                    route_distinguisher=dict(\n                        type='str'\n                    ),\n                    route_targets=dict(\n                        type='list',\n                        elements='dict',\n                        options=dict(\n                            description=dict(\n                                type='str',\n                                default=\"\"\n                            ),\n                            display_name=dict(\n                                type='str',\n                            ),\n                            export_route_targets=dict(\n                                type='list',\n                            ),\n                            id=dict(\n                                type='str',\n                            ),\n                            import_route_targets=dict(\n                                type='list',\n                            ),\n                            tags=dict(\n                                type='list',\n                                elements='dict',\n                                options=dict(\n                                    scope=dict(\n                                        type='str',\n                                    ),\n                                    tag=dict(\n                                        type='str',\n                                    ),\n                                )\n                            ),\n                        )\n                    ),\n                    tags=dict(\n                        type='list',\n                        elements='dict',\n                        options=dict(\n                            scope=dict(\n                                type='str',\n                            ),\n                            tag=dict(\n                                type='str',\n                            ),\n                        )\n                    ),\n                    tier0_display_name=dict(\n                        type='str'\n                    ),\n                    tier0_id=dict(\n                        type='str'\n                    ),\n                )\n            ),\n        )\n        return tier0_arg_spec\n\n    @staticmethod\n    def get_resource_base_url(baseline_args=None):\n        return TIER_0_URL\n\n    def update_resource_params(self, nsx_resource_params):\n        ipv6_profile_paths = []\n        if self.do_resource_params_have_attr_with_id_or_display_name(\n                \"ipv6_ndra_profile\"):\n            ipv6_ndra_profile_id = self.get_id_using_attr_name_else_fail(\n                    \"ipv6_ndra_profile\", nsx_resource_params,\n                    IPV6_NDRA_PROFILE_URL, \"Ipv6NdraProfile\")\n            ipv6_profile_paths.append(\n                IPV6_NDRA_PROFILE_URL + \"/\" + ipv6_ndra_profile_id)\n        if self.do_resource_params_have_attr_with_id_or_display_name(\n                \"ipv6_dad_profile\"):\n            ipv6_dad_profile_id = self.get_id_using_attr_name_else_fail(\n                    \"ipv6_dad_profile\", nsx_resource_params,\n                    IPV6_DAD_PROFILE_URL, \"Ipv6DadProfile\")\n            ipv6_profile_paths.append(\n                IPV6_DAD_PROFILE_URL + \"/\" + ipv6_dad_profile_id)\n        if ipv6_profile_paths:\n            nsx_resource_params[\"ipv6_profile_paths\"] = ipv6_profile_paths\n\n        if self.do_resource_params_have_attr_with_id_or_display_name(\n                \"dhcp_config\"):\n            dhcp_config_id = self.get_id_using_attr_name_else_fail(\n                \"dhcp_config\", nsx_resource_params,\n                DHCP_RELAY_CONFIG_URL, \"DhcpRelayConfig\")\n            nsx_resource_params[\"dhcp_config_paths\"] = [\n                DHCP_RELAY_CONFIG_URL + \"/\" + dhcp_config_id]\n\n        if 'vrf_config' in nsx_resource_params:\n            # vrf config is attached\n            vrf_config = nsx_resource_params['vrf_config']\n\n            vrf_id = vrf_config.get('id')\n            vrf_display_name = vrf_config.get('display_name')\n            if not (vrf_display_name or vrf_id):\n                self.exit_with_failure(msg=\"Please specify either the ID or \"\n                                       \"display_name of the VRF in the \"\n                                       \"vrf_config using id or display_name\")\n\n            tier0_id = vrf_config.pop('tier0_id', None)\n            if not tier0_id:\n                tier0_id = self.get_id_using_attr_name_else_fail(\n                    'tier0', vrf_config, NSXTTier0.get_resource_base_url(),\n                    'Tier0')\n            vrf_config['tier0_path'] = (\n                NSXTTier0.get_resource_base_url() + \"/\" + tier0_id)\n\n            vrf_config['resource_type'] = 'Tier0VrfConfig'\n\n            if 'route_targets' in vrf_config:\n                route_targets = vrf_config['route_targets'] or []\n                for route_target in route_targets:\n                    route_target['resource_type'] = 'VrfRouteTargets'\n\n    def update_parent_info(self, parent_info):\n        parent_info[\"tier0_id\"] = self.id\n\n    class NSXTTier0StaticRoutes(NSXTBaseRealizableResource):\n        @staticmethod\n        def get_resource_update_priority():\n            # Create this first\n            return 2\n\n        def get_spec_identifier(self):\n            return NSXTTier0.NSXTTier0StaticRoutes.get_spec_identifier()\n\n        @classmethod\n        def get_spec_identifier(cls):\n            return \"static_routes\"\n\n        @staticmethod\n        def get_resource_spec():\n            tier0_sr_arg_spec = {}\n            tier0_sr_arg_spec.update(\n                network=dict(\n                    required=True,\n                    type='str'\n                ),\n                next_hops=dict(\n                    required=True,\n                    type='list',\n                    elements='dict',\n                    options=dict(\n                        admin_distance=dict(\n                            type='int',\n                            default=1\n                        ),\n                        ip_address=dict(\n                            type='str'\n                        ),\n                        scope=dict(\n                            type='list',\n                            elements='str'\n                        )\n                    )\n                ),\n            )\n            return tier0_sr_arg_spec\n\n        @staticmethod\n        def get_resource_base_url(parent_info):\n            tier0_id = parent_info.get(\"tier0_id\", 'default')\n            return TIER_0_STATIC_ROUTE_URL.format(tier0_id)\n\n        def update_parent_info(self, parent_info):\n            parent_info[\"sr_id\"] = self.id\n\n    class NSXTTier0SRBFDPeer(NSXTBaseRealizableResource):\n        def get_spec_identifier(self):\n            return (NSXTTier0.NSXTTier0StaticRoutes.NSXTTier0SRVFDPeer.\n                    get_spec_identifier())\n\n        @classmethod\n        def get_spec_identifier(cls):\n            return \"bfd_peers\"\n\n        @staticmethod\n        def get_resource_spec():\n            tier0_sr_bfd_peer_arg_spec = {}\n            tier0_sr_bfd_peer_arg_spec.update(\n                bfd_profile_id=dict(\n                    type='str'\n                ),\n                bfd_profile_display_name=dict(\n                    type='str'\n                ),\n                enabled=dict(\n                    type='bool',\n                    default=True\n                ),\n                peer_address=dict(\n                    type='str',\n                    required=True\n                ),\n                source_addresses=dict(\n                    type='list',\n                ),\n            )\n            return tier0_sr_bfd_peer_arg_spec\n\n        @staticmethod\n        def get_resource_base_url(parent_info):\n            tier0_id = parent_info.get(\"tier0_id\", 'default')\n            return TIER_0_BFD_PEERS.format(tier0_id)\n\n        def update_resource_params(self, nsx_resource_params):\n            bfd_profile_id = self.get_id_using_attr_name_else_fail(\n                \"bfd_profile\", nsx_resource_params, '/infra/bfd-profiles',\n                'BFD Profile')\n            nsx_resource_params.pop('bfd_profile_id', None)\n            nsx_resource_params.pop('bfd_profile_display_name', None)\n            nsx_resource_params['bfd_profile_path'] = (\n                '/infra/bfd-profiles/{}'.format(bfd_profile_id))\n\n    class NSXTTier0LocaleService(NSXTBaseRealizableResource):\n        def get_spec_identifier(self):\n            return NSXTTier0.NSXTTier0LocaleService.get_spec_identifier()\n\n        @classmethod\n        def get_spec_identifier(cls):\n            return \"locale_services\"\n\n        def infer_resource_id(self, parent_info):\n            all_locale_services = self.get_all_resources_from_nsx()\n            if len(all_locale_services) == 0:\n                self.module.fail_json(\n                    msg=\"No {} found under Tier0 gateway {}. Please specify \"\n                        \"the id or display_name of the LocaleService to be \"\n                        \"created\".format(\n                            self.get_spec_identifier(),\n                            parent_info.get(\"tier0_id\", 'default')))\n            if len(all_locale_services) > 1:\n                ls_ids = [ls['id'] for ls in all_locale_services]\n                self.module.fail_json(\n                    msg=\"Multiple {} found under Tier0 gateway {} with IDs \"\n                        \"{}. Please specify the id of the LocaleService \"\n                        \"to be updated\".format(\n                            self.get_spec_identifier(),\n                            parent_info.get(\"tier0_id\", 'default'), ls_ids))\n            return all_locale_services[0]['id']\n\n        @staticmethod\n        def get_resource_spec():\n            tier0_ls_arg_spec = {}\n            tier0_ls_arg_spec.update(\n                edge_cluster_info=dict(\n                    required=False,\n                    type='dict',\n                    options=dict(\n                        # Note that only default site_id and\n                        # enforcementpoint_id are used\n                        site_id=dict(\n                            type='str',\n                            default=\"default\"\n                        ),\n                        enforcementpoint_id=dict(\n                            type='str',\n                            default=\"default\"\n                        ),\n                        edge_cluster_id=dict(\n                            type='str'\n                        ),\n                        edge_cluster_display_name=dict(\n                            type='str'\n                        )\n                    )\n                ),\n                preferred_edge_nodes_info=dict(\n                    required=False,\n                    type='list',\n                    elements='dict',\n                    options=dict(\n                        # Note that only default site_id and\n                        # enforcementpoint_id are used\n                        site_id=dict(\n                            type='str',\n                            default=\"default\"\n                        ),\n                        enforcementpoint_id=dict(\n                            type='str',\n                            default=\"default\"\n                        ),\n                        edge_cluster_id=dict(\n                            type='str'\n                        ),\n                        edge_cluster_display_name=dict(\n                            type='str'\n                        ),\n                        edge_node_id=dict(\n                            type='str'\n                        ),\n                        edge_node_display_name=dict(\n                            type='str'\n                        )\n                    )\n                ),\n                route_redistribution_types=dict(\n                    required=False,\n                    type='list',\n                    elements='str',\n                ),\n                route_redistribution_config=dict(\n                    type='dict',\n                    required=False,\n                    options=dict(\n                        bgp_enabled=dict(\n                            type='bool',\n                            default=False\n                        ),\n                        redistribution_rules=dict(\n                            type='list',\n                            required=False,\n                            elements='dict',\n                            options=dict(\n                                name=dict(\n                                    type='str',\n                                    required=False\n                                ),\n                                route_map_path=dict(\n                                    type='str',\n                                    required=False\n                                ),\n                                route_redistribution_types=dict(\n                                    type='list',\n                                    elements='str',\n                                    required=False\n                                ),\n                            )\n                        )\n                    )\n                ),\n                ha_vip_configs=dict(\n                    type='list',\n                    elements='dict',\n                    options=dict(\n                        enabled=dict(\n                            default=True,\n                            type='bool'\n                        ),\n                        external_interface_info=dict(\n                            required=True,\n                            type='list',\n                            elements='dict',\n                            options=dict(\n                                id=dict(\n                                    type='str'\n                                ),\n                                display_name=dict(\n                                    type='str'\n                                )\n                            )\n                        ),\n                        vip_subnets=dict(\n                            type='list',\n                            elements='dict',\n                            required=True,\n                            options=dict(\n                                ip_addresses=dict(\n                                    type='list',\n                                    required=True\n                                ),\n                                prefix_len=dict(\n                                    type='int',\n                                    rqeuired=True\n                                )\n                            )\n                        ),\n                    )\n                )\n            )\n            return tier0_ls_arg_spec\n\n        @staticmethod\n        def get_resource_base_url(parent_info):\n            tier0_id = parent_info.get(\"tier0_id\", 'default')\n            return TIER_0_LOCALE_SERVICE_URL.format(tier0_id)\n\n        def update_resource_params(self, nsx_resource_params):\n            if \"edge_cluster_info\" in nsx_resource_params:\n                edge_cluster_info = nsx_resource_params.pop(\n                    \"edge_cluster_info\")\n                site_id = edge_cluster_info[\"site_id\"]\n                enforcementpoint_id = edge_cluster_info[\"enforcementpoint_id\"]\n                edge_cluster_base_url = (\n                    EDGE_CLUSTER_URL.format(site_id, enforcementpoint_id))\n                edge_cluster_id = self.get_id_using_attr_name_else_fail(\n                    \"edge_cluster\", edge_cluster_info, edge_cluster_base_url,\n                    \"Edge Cluster\")\n                nsx_resource_params[\"edge_cluster_path\"] = (\n                    edge_cluster_base_url + \"/\" + edge_cluster_id)\n\n            if \"preferred_edge_nodes_info\" in nsx_resource_params:\n                preferred_edge_nodes_info = nsx_resource_params.pop(\n                    \"preferred_edge_nodes_info\")\n                nsx_resource_params[\"preferred_edge_paths\"] = []\n                for preferred_edge_node_info in preferred_edge_nodes_info:\n                    site_id = preferred_edge_node_info.get(\n                        \"site_id\", \"default\")\n                    enforcementpoint_id = preferred_edge_node_info.get(\n                        \"enforcementpoint_id\", \"default\")\n                    edge_cluster_base_url = (\n                        EDGE_CLUSTER_URL.format(site_id, enforcementpoint_id))\n                    edge_cluster_id = self.get_id_using_attr_name_else_fail(\n                        \"edge_cluster\", preferred_edge_node_info,\n                        edge_cluster_base_url, \"Edge Cluster\")\n                    edge_node_base_url = EDGE_NODE_URL.format(\n                        site_id, enforcementpoint_id, edge_cluster_id)\n                    edge_node_id = self.get_id_using_attr_name_else_fail(\n                        \"edge_node\", preferred_edge_node_info,\n                        edge_node_base_url, \"Edge Node\")\n                    nsx_resource_params[\"preferred_edge_paths\"].append(\n                        edge_node_base_url + \"/\" + edge_node_id)\n\n            if 'ha_vip_configs' in nsx_resource_params:\n                for ha_vip_config in nsx_resource_params['ha_vip_configs']:\n                    external_interface_info = ha_vip_config.pop(\n                        'external_interface_info')\n                    external_interface_paths = []\n                    for external_interface in (\n                            external_interface_info):\n                        interface_base_url = (\n                            NSXTTier0.NSXTTier0LocaleService.\n                            NSXTTier0Interface.get_resource_base_url(\n                                self.get_parent_info()))\n                        external_interface_paths.append(\n                            interface_base_url + \"/\" +\n                            self.get_id_using_attr_name_else_fail(\n                                None, external_interface,\n                                interface_base_url,\n                                NSXTTier0.NSXTTier0LocaleService.\n                                NSXTTier0Interface.__name__))\n                    ha_vip_config[\n                        'external_interface_paths'] = external_interface_paths\n\n        def update_parent_info(self, parent_info):\n            parent_info[\"ls_id\"] = self.id\n\n        class NSXTTier0Interface(NSXTBaseRealizableResource):\n            def get_spec_identifier(self):\n                return (\n                    NSXTTier0.NSXTTier0LocaleService.NSXTTier0Interface.\n                    get_spec_identifier())\n\n            @classmethod\n            def get_spec_identifier(cls):\n                return \"interfaces\"\n\n            @staticmethod\n            def get_resource_spec():\n                tier0_ls_int_arg_spec = {}\n                tier0_ls_int_arg_spec.update(\n                    access_vlan_id=dict(\n                        type='int'\n                    ),\n                    ipv6_ndra_profile_display_name=dict(\n                        type='str'\n                    ),\n                    ipv6_ndra_profile_id=dict(\n                        type='str'\n                    ),\n                    mtu=dict(\n                        type='int'\n                    ),\n                    multicast=dict(\n                        type='dict',\n                        suboptions=dict(\n                            enabled=dict(\n                                type='bool',\n                                default=False\n                            )\n                        )\n                    ),\n                    segment_id=dict(\n                        type='str'\n                    ),\n                    segment_display_name=dict(\n                        type='str'\n                    ),\n                    edge_node_info=dict(\n                        required=True,\n                        type='dict',\n                        options=dict(\n                            site_id=dict(\n                                type='str',\n                                default=\"default\"\n                            ),\n                            enforcementpoint_id=dict(\n                                type='str',\n                                default=\"default\"\n                            ),\n                            edge_cluster_id=dict(\n                                type='str'\n                            ),\n                            edge_cluster_display_name=dict(\n                                type='str'\n                            ),\n                            edge_node_id=dict(\n                                type='str'\n                            ),\n                            edge_node_display_name=dict(\n                                type='str'\n                            )\n                        )\n                    ),\n                    subnets=dict(\n                        required=True,\n                        type='list',\n                        elements='dict',\n                        options=dict(\n                            ip_addresses=dict(\n                                type='list',\n                                elements='str'\n                            ),\n                            prefix_len=dict(\n                                type='int'\n                            )\n                        )\n                    ),\n                    type=dict(\n                        type='str',\n                        default=\"EXTERNAL\",\n                        choices=[\"EXTERNAL\", \"SERVICE\", \"LOOPBACK\"]\n                    ),\n                    urpf_mode=dict(\n                        type='str',\n                        default='STRICT',\n                        choices=['NONE', 'STRICT']\n                    )\n                )\n                return tier0_ls_int_arg_spec\n\n            @staticmethod\n            def get_resource_base_url(parent_info):\n                tier0_id = parent_info.get(\"tier0_id\", 'default')\n                locale_service_id = parent_info.get(\"ls_id\", 'default')\n                return TIER_0_LS_INTERFACE_URL.format(\n                    tier0_id, locale_service_id)\n\n            def update_resource_params(self, nsx_resource_params):\n                ipv6_profile_paths = []\n                if self.do_resource_params_have_attr_with_id_or_display_name(\n                        \"ipv6_ndra_profile\"):\n                    ipv6_ndra_profile_id = (\n                        self.get_id_using_attr_name_else_fail(\n                            \"ipv6_ndra_profile\", nsx_resource_params,\n                            IPV6_NDRA_PROFILE_URL, \"Ipv6NdraProfile\"))\n                    ipv6_profile_paths.append(\n                        IPV6_NDRA_PROFILE_URL + \"/\" + ipv6_ndra_profile_id)\n                if ipv6_profile_paths:\n                    nsx_resource_params[\n                        \"ipv6_profile_paths\"] = ipv6_profile_paths\n\n                # segment_id is a required attr\n                segment_id = self.get_id_using_attr_name_else_fail(\n                    \"segment\", nsx_resource_params, SEGMENT_URL, \"Segment\")\n                nsx_resource_params[\"segment_path\"] = (\n                    SEGMENT_URL + \"/\" + segment_id)\n\n                # edge_node_info is a required attr\n                edge_node_info = nsx_resource_params.pop(\"edge_node_info\")\n                site_id = edge_node_info.get(\"site_id\", \"default\")\n                enforcementpoint_id = edge_node_info.get(\n                    \"enforcementpoint_id\", \"default\")\n                edge_cluster_base_url = (\n                    EDGE_CLUSTER_URL.format(site_id, enforcementpoint_id))\n                edge_cluster_id = self.get_id_using_attr_name_else_fail(\n                    \"edge_cluster\", edge_node_info,\n                    edge_cluster_base_url, \"Edge Cluster\")\n                edge_node_base_url = EDGE_NODE_URL.format(\n                    site_id, enforcementpoint_id, edge_cluster_id)\n                edge_node_id = self.get_id_using_attr_name_else_fail(\n                    \"edge_node\", edge_node_info, edge_node_base_url,\n                    'Edge Node')\n                nsx_resource_params[\"edge_path\"] = (\n                    edge_node_base_url + \"/\" + edge_node_id)\n\n        class NSXTTier0LocaleServiceBGP(NSXTBaseRealizableResource):\n            def __init__(self):\n                self.id = 'bgp'\n                super().__init__()\n\n            def skip_delete(self):\n                return True\n\n            def get_spec_identifier(self):\n                return (\n                    NSXTTier0.NSXTTier0LocaleService.NSXTTier0LocaleServiceBGP.\n                    get_spec_identifier())\n\n            @classmethod\n            def get_spec_identifier(cls):\n                return \"BGP\"\n\n            @staticmethod\n            def get_resource_spec():\n                tier0_ls_arg_spec = {}\n                tier0_ls_arg_spec.update(\n                    ecmp=dict(\n                        default=True,\n                        type='bool'\n                    ),\n                    enabled=dict(\n                        default=True,\n                        type='bool'\n                    ),\n                    graceful_restart_config=dict(\n                        required=False,\n                        type='dict',\n                        options=dict(\n                            mode=dict(\n                                required=False,\n                                type='str',\n                                choices=['DISABLE', 'GR_AND_HELPER',\n                                         'HELPER_ONLY'],\n                                default='HELPER_ONLY'\n                            ),\n                            timer=dict(\n                                required=False,\n                                type='dict',\n                                options=dict(\n                                    restart_timer=dict(\n                                        required=False,\n                                        type='int',\n                                        default=180\n                                    ),\n                                    stale_route_timer=dict(\n                                        required=False,\n                                        type='int',\n                                        default=600\n                                    ),\n                                )\n                            )\n                        )\n                    ),\n                    inter_sr_ibgp=dict(\n                        required=False,\n                        type='bool'\n                    ),\n                    local_as_num=dict(\n                        type='str'\n                    ),\n                    multipath_relax=dict(\n                        type='bool',\n                        default=True\n                    ),\n                    route_aggregations=dict(\n                        required=False,\n                        type='list',\n                        elements='dict',\n                        options=dict(\n                            prefix=dict(\n                                required=True,\n                                type='str'\n                            ),\n                            summary_only=dict(\n                                type='bool',\n                                default=True\n                            )\n                        )\n                    )\n                )\n                return tier0_ls_arg_spec\n\n            @staticmethod\n            def get_resource_base_url(parent_info):\n                tier0_id = parent_info.get(\"tier0_id\", 'default')\n                locale_service_id = parent_info.get(\"ls_id\", 'default')\n                return (TIER_0_LOCALE_SERVICE_URL + '/{}').format(\n                    tier0_id, locale_service_id)\n\n            @classmethod\n            def allows_multiple_resource_spec(cls):\n                return False\n\n            class NSXTTier0LocaleServiceBGPNeighbor(\n                    NSXTBaseRealizableResource):\n                def get_spec_identifier(self):\n                    return (\n                        NSXTTier0.NSXTTier0LocaleService.\n                        NSXTTier0LocaleServiceBGP.\n                        get_spec_identifier())\n\n                @classmethod\n                def get_spec_identifier(cls):\n                    return \"neighbors\"\n\n                @staticmethod\n                def get_resource_spec():\n                    tier0_ls_arg_spec = {}\n                    tier0_ls_arg_spec.update(\n                        allow_as_in=dict(\n                            default=False,\n                            type='bool'\n                        ),\n                        bfd=dict(\n                            type='dict',\n                            required=False,\n                            options=dict(\n                                enabled=dict(\n                                    required=False,\n                                    default=False,\n                                    type='bool'\n                                ),\n                                interval=dict(\n                                    required=False,\n                                    type='int',\n                                    default=1000\n                                ),\n                                multiple=dict(\n                                    required=False,\n                                    type='int',\n                                    default=3\n                                )\n                            )\n                        ),\n                        graceful_restart_mode=dict(\n                            type='str',\n                            required=False,\n                            choices=['DISABLE', 'GR_AND_HELPER', 'HELPER_ONLY']\n                        ),\n                        hold_down_time=dict(\n                            type='int',\n                            default=180\n                        ),\n                        keep_alive_time=dict(\n                            type='int',\n                            default=60\n                        ),\n                        maximum_hop_limit=dict(\n                            type='int',\n                            default=1\n                        ),\n                        password=dict(\n                            type='str',\n                            required=False\n                        ),\n                        remote_as_num=dict(\n                            required=True,\n                            type='str'\n                        ),\n                        route_filtering=dict(\n                            required=False,\n                            type='list',\n                            elements='dict',\n                            options=dict(\n                                address_family=dict(\n                                    required=False,\n                                    type='str',\n                                    choices=['IPV4', 'IPV6', 'VPN']\n                                ),\n                                enabled=dict(\n                                    type='bool',\n                                    default=True,\n                                    required=False\n                                ),\n                                in_route_filters=dict(\n                                    type='list',\n                                    required=False\n                                ),\n                                out_route_filters=dict(\n                                    type='list',\n                                    required=False\n                                )\n                            )\n                        ),\n                        source_addresses=dict(\n                            required=False,\n                            type='list'\n                        ),\n                        neighbor_address=dict(\n                            required=True,\n                            type='str'\n                        )\n                    )\n                    return tier0_ls_arg_spec\n\n                @staticmethod\n                def get_resource_base_url(parent_info):\n                    tier0_id = parent_info.get(\"tier0_id\", 'default')\n                    locale_service_id = parent_info.get(\"ls_id\", 'default')\n                    return TIER_0_BGP_NEIGHBOR_URL.format(\n                        tier0_id, locale_service_id)\n\n\nif __name__ == '__main__':\n    nsxt_tier0 = NSXTTier0()\n    nsxt_tier0.realize()\n"
  },
  {
    "path": "plugins/modules/nsxt_policy_tier1.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\nmodule: nsxt_policy_tier1\nshort_description: 'Create/Update/Delete a Tier-1 and associated resources'\ndescription: Creates/Updates/Deletes a Tier-1 resource using the Policy API.\n             Assocaited resources include 'Tier-1 Locale Service' and\n             'Tier-1 Interface'. 'Tier-1 Locale Service' and 'Tier-1 Interface'\n             attributes must be prepended with 't1ls' and 't1iface'\n             respectively.\nversion_added: '2.8'\nauthor: 'Gautam Verma'\nextends_documentation_fragment:\n    - vmware.ansible_for_nsxt.vmware_nsxt\noptions:\n    id:\n        description: Tier-1 ID\n        required: false\n        type: str\n    description:\n        description: Tier-1 description\n        type: str\n    default_rule_logging:\n        description: Enable logging for whitelisted rule.\n                     Indicates if logging should be enabled for the default\n                     whitelisting rule.\n        default: false\n    disable_firewall:\n        description: Disable or enable gateway fiewall.\n        default: False\n        type: bool\n    failover_mode:\n        description: Determines the behavior when a Tier-1 instance in\n                     ACTIVE-STANDBY high-availability mode restarts\n                     after a failure. If set to PREEMPTIVE, the preferred node\n                     will take over, even if it causes\n                     another failure. If set to NON_PREEMPTIVE, then\n                     the instance that restarted will remain secondary.\n                     This property must not be populated unless the\n                     ha_mode property is set to ACTIVE_STANDBY.\n        choices:\n            - 'NON_PREEMPTIVE'\n            - 'PREEMPTIVE'\n        default: 'NON_PREEMPTIVE'\n        type: str\n    enable_standby_relocation:\n        description:\n            - Flag to enable standby service router relocation.\n            - Standby relocation is not enabled until edge cluster is\n              configured for Tier1.\n        type: bool\n        default: false\n    force_whitelisting:\n        description: Flag to add whitelisting FW rule during\n                     realization.\n        default: False\n        type: bool\n    intersite_config:\n        description: Inter site routing configuration when the gateway is\n                     streched.\n        type: dict\n        suboptions:\n            fallback_sites:\n                description: Fallback site to be used as new primary\n                             site on current primary site failure.\n                             Disaster recovery must be initiated via\n                             API/UI. Fallback site configuration is\n                             supported only for T0 gateway. T1 gateway\n                             will follow T0 gateway's primary site\n                             during disaster recovery\n                type: list\n            intersite_transit_subnet:\n                description:\n                    - Transit subnet in CIDR format\n                    - IPv4 subnet for inter-site transit segment\n                      connecting service routers across sites for\n                      stretched gateway. For IPv6 link local subnet is\n                      auto configured\n                type: str\n                default: \"169.254.32.0/20\"\n            last_admin_active_epoch:\n                description:\n                    - Epoch of last time admin changing active\n                      LocaleServices\n                    - Epoch(in seconds) is auto updated based on\n                      system current timestamp when primary locale\n                      service is updated. It is used for resolving\n                      conflict during site failover. If system clock\n                      not in sync then User can optionally override\n                      this. New value must be higher than the current\n                      value.\n                type: int\n            primary_site_path:\n                description:\n                    - Primary egress site for gateway.\n                    - Primary egress site for gateway. T0/T1 gateway in\n                      Active/Standby mode supports stateful services on primary\n                      site. In this mode primary site must be set if gateway is\n                      stretched to more than one site. For T0 gateway in\n                      Active/Active primary site is optional field. If set then\n                      secondary site prefers routes learned from primary over\n                      locally learned routes. This field is not applicable for\n                      T1 gateway with no services\n                type: str\n    ipv6_ndra_profile_id:\n        description: IPv6 NDRA profile configuration on Tier1.\n                     Either or both NDRA and/or DAD profiles can be\n                     configured. Related attribute ipv6_dad_profile_id.\n        type: str\n    ipv6_ndra_profile_display_name:\n        description: Same as ipv6_ndra_profile_id. Either one can be specified.\n                     If both are specified, ipv6_ndra_profile_id takes\n                     precedence.\n        type: str\n    ipv6_dad_profile_id:\n        description: IPv6 DRA profile configuration on Tier1.\n                     Either or both NDRA and/or DAD profiles can be\n                     configured. Related attribute ipv6_ndra_profile_id.\n        type: str\n    ipv6_dad_profile_display_name:\n        description: Same as ipv6_dad_profile_id. Either one can be specified.\n                     If both are specified, ipv6_dad_profile_id takes\n                     precedence.\n        type: str\n    dhcp_config_id:\n        description: DHCP configuration for Segments connected to\n                     Tier-1. DHCP service is configured in relay mode.\n        type: str\n    dhcp_config_display_name:\n        description: Same as dhcp_config_id. Either one can be specified.\n                     If both are specified, dhcp_config_id takes precedence.\n        type: str\n    pool_allocation:\n        description:\n            - Edge node allocation size\n            - Supports edge node allocation at different sizes for routing and\n              load balancer service to meet performance and scalability\n              requirements.\n            - ROUTING - Allocate edge node to provide routing services.\n            - LB_SMALL, LB_MEDIUM, LB_LARGE, LB_XLARGE - Specify size of load\n              balancer service that will be configured on TIER1 gateway.\n        type: str\n        choices:\n            - ROUTING\n            - LB_SMALL\n            - LB_MEDIUM\n            - LB_LARGE\n            - LB_XLARGE\n        default: ROUTING\n    qos_profile:\n        description: QoS Profile configuration for Tier1 router link connected\n                     to Tier0 gateway.\n        type: dict\n        suboptions:\n            egress_qos_profile_path:\n                description: Policy path to gateway QoS profile in egress\n                             direction.\n                type: str\n            ingress_qos_profile_path:\n                description: Policy path to gateway QoS profile in ingress\n                             direction.\n                type: str\n    route_advertisement_rules:\n        description: Route advertisement rules and filtering\n        type: list\n        suboptions:\n            action:\n                description:\n                    - Action to advertise filtered routes to the connected\n                      Tier0 gateway.\n                choices:\n                    - PERMIT: Enables the advertisment\n                    - DENY: Disables the advertisement\n                type: str\n                required: true\n            name:\n                description: Display name for rule\n                type: str\n                required: true\n            prefix_operator:\n                description:\n                    - Prefix operator to filter subnets.\n                    - GE prefix operator filters all the routes with prefix\n                      length greater than or equal to the subnets configured.\n                    - EQ prefix operator filter all the routes with prefix\n                      length equal to the subnets configured.\n                type: str\n                choices:\n                    - GE\n                    - EQ\n            route_advertisement_types:\n                description:\n                    - Enable different types of route advertisements.\n                    - By default, Routes to IPSec VPN local-endpoint subnets\n                      (TIER1_IPSEC_LOCAL_ENDPOINT) are advertised if no value\n                      is supplied here.\n                type: list\n                choices:\n                    - 'TIER1_STATIC_ROUTES'\n                    - 'TIER1_CONNECTED'\n                    - 'TIER1_NAT'\n                    - 'TIER1_LB_VIP'\n                    - 'TIER1_LB_SNAT'\n                    - 'TIER1_DNS_FORWARDER_IP'\n                    - 'TIER1_IPSEC_LOCAL_ENDPOINT'\n            subnets:\n                description: Network CIDRs to be routed.\n                type: list\n    route_advertisement_types:\n        description:\n            - Enable different types of route advertisements.\n            - By default, Routes to IPSec VPN local-endpoint subnets\n              (TIER1_IPSEC_LOCAL_ENDPOINT) are advertised if no value is\n              supplied here.\n        type: list\n        choices:\n            - 'TIER1_STATIC_ROUTES'\n            - 'TIER1_CONNECTED'\n            - 'TIER1_NAT'\n            - 'TIER1_LB_VIP'\n            - 'TIER1_LB_SNAT'\n            - 'TIER1_DNS_FORWARDER_IP'\n            - 'TIER1_IPSEC_LOCAL_ENDPOINT'\n    tier0_id:\n        description: Tier-1 connectivity to Tier-0\n        type: str\n    tier0_display_name:\n        description: Same as tier0_id. Either one can be specified.\n                    If both are specified, tier0_id takes precedence.\n        type: str\n    static_routes:\n        type: list\n        element: dict\n        description: This is a list of Static Routes that need to be created,\n                     updated, or deleted\n        suboptions:\n            id:\n                description: Tier-1 Static Route ID.\n                required: false\n                type: str\n            display_name:\n                description:\n                    - Tier-1 Static Route display name.\n                    - Either this or id must be specified. If both are\n                      specified, id takes precedence.\n                required: false\n                type: str\n            description:\n                description:\n                    - Tier-1 Static Route description.\n                type: str\n            state:\n                description:\n                    - State can be either 'present' or 'absent'. 'present' is\n                      used to create or update resource. 'absent' is used to\n                      delete resource.\n                    - Must be specified in order to modify the resource\n                choices:\n                    - present\n                    - absent\n            network:\n                description: Network address in CIDR format\n                required: true\n                type: str\n            next_hops:\n                description: Next hop routes for network\n                type: list\n                elements: dict\n                suboptions:\n                    admin_distance:\n                        description: Cost associated with next hop route\n                        type: int\n                        default: 1\n                ip_address:\n                    description: Next hop gateway IP address\n                    type: str\n                scope:\n                    description:\n                        - Interface path associated with current route\n                        - For example, specify a policy path referencing the\n                          IPSec VPN Session\n                    type: list\n            tags:\n                description: Opaque identifiers meaningful to the API user\n                type: dict\n                suboptions:\n                    scope:\n                        description: Tag scope.\n                        required: true\n                        type: str\n                    tag:\n                        description: Tag value.\n                        required: true\n                        type: str\n            achieve_subresource_state_if_del_parent:\n                type: bool\n                default: false\n                description:\n                    - Can be used to achieve the state of subresources even if\n                      the parent(base) resource's state is absent.\n                    - Can be specified for each subresource.\n            do_wait_till_create:\n                type: bool\n                default: false\n                description:\n                    - Can be used to wait for the realization of subresource\n                      before the request to create the next resource is sent to\n                      the Manager\n    locale_services:\n        type: list\n        element: dict\n        description: This is a list of Locale Services that need to be created,\n                     updated, or deleted\n        suboptions:\n            id:\n                description: Tier-1 Locale Service ID\n                type: str\n            display_name:\n                description:\n                    - Tier-1 Locale Service display name.\n                    - Either this or id must be specified. If both are\n                      specified, id takes precedence.\n                required: false\n                type: str\n            description:\n                description: Tier-1 Locale Service  description\n                type: str\n            state:\n                description:\n                    - State can be either 'present' or 'absent'. 'present' is\n                      used to create or update resource. 'absent' is used to\n                      delete resource.\n                    - Required if I(segp_id != null)\n                choices:\n                    - present\n                    - absent\n            tags:\n                description: Opaque identifiers meaningful to the API user.\n                type: dict\n                suboptions:\n                    scope:\n                        description: Tag scope.\n                        required: true\n                        type: str\n                    tag:\n                        description: Tag value.\n                        required: true\n                        type: str\n            achieve_subresource_state_if_del_parent:\n                type: bool\n                default: false\n                description:\n                    - Can be used to achieve the state of subresources even if\n                      the parent(base) resource's state is absent.\n                    - Can be specified for each subresource.\n            do_wait_till_create:\n                type: bool\n                default: false\n                description:\n                    - Can be used to wait for the realization of subresource\n                      before the request to create the next resource is sent to\n                      the Manager\n            edge_cluster_info:\n                description: Used to create path to edge cluster. Auto-assigned\n                             if associated enforcement-point has only one edge\n                             cluster.\n                type: dict\n                suboptions:\n                    site_id:\n                        description: site_id where edge cluster is located\n                        default: default\n                        type: str\n                    enforcementpoint_id:\n                        description: enforcementpoint_id where edge cluster is\n                                     located\n                        default: default\n                        type: str\n                    edge_cluster_id:\n                        description: ID of the edge cluster\n                        required: true\n                        type: str\n                    edge_cluster_display_name:\n                        description:\n                            - display name of the edge cluster.\n                            - Either this or edge_cluster_id must be specified.\n                              If both are specified, edge_cluster_id takes\n                              precedence\n                        type: str\n            preferred_edge_nodes_info:\n                description: Used to create paths to edge nodes. Specified edge\n                             is used as preferred edge cluster member when\n                             failover mode is set to PREEMPTIVE, not\n                             applicable otherwise.\n                type: list\n                suboptions:\n                    site_id:\n                        description: site_id where edge node is located\n                        default: default\n                        type: str\n                    enforcementpoint_id:\n                        description: enforcementpoint_id where edge node is\n                                     located\n                        default: default\n                        type: str\n                    edge_cluster_id:\n                        description: edge_cluster_id where edge node is\n                                     located\n                        required: true\n                        type: str\n                    edge_cluster_display_name:\n                        description:\n                            - display name of the edge cluster.\n                            - either this or edge_cluster_id must be specified.\n                              If both are specified, edge_cluster_id takes\n                              precedence\n                        type: str\n                    edge_node_id:\n                        description: ID of the edge node\n                        type: str\n                    edge_node_display_name:\n                        description:\n                            - Display name of the edge node.\n                            - either this or edge_node_id must be specified. If\n                              both are specified, edge_node_id takes precedence\n                        type: str\n            route_redistribution_types:\n                description:\n                    - Enable redistribution of different types of routes on\n                      Tier-0.\n                    - This property is only valid for locale-service under\n                      Tier-0.\n                    - This property is deprecated, please use\n                      \"route_redistribution_config\" property to configure\n                      redistribution rules.\n                choices:\n                    - TIER0_STATIC - Redistribute user added\n                        static routes.\n                    - TIER0_CONNECTED - Redistribute all\n                        subnets configured on Interfaces and\n                        routes related to TIER0_ROUTER_LINK,\n                        TIER0_SEGMENT, TIER0_DNS_FORWARDER_IP,\n                        TIER0_IPSEC_LOCAL_IP, TIER0_NAT types.\n                    - TIER1_STATIC - Redistribute all subnets\n                        and static routes advertised by Tier-1s.\n                    - TIER0_EXTERNAL_INTERFACE - Redistribute\n                        external interface subnets on Tier-0.\n                    - TIER0_LOOPBACK_INTERFACE - Redistribute\n                        loopback interface subnets on Tier-0.\n                    - TIER0_SEGMENT - Redistribute subnets\n                        configured on Segments connected to\n                        Tier-0.\n                    - TIER0_ROUTER_LINK - Redistribute router\n                        link port subnets on Tier-0.\n                    - TIER0_SERVICE_INTERFACE - Redistribute\n                        Tier0 service interface subnets.\n                    - TIER0_DNS_FORWARDER_IP - Redistribute DNS\n                        forwarder subnets.\n                    - TIER0_IPSEC_LOCAL_IP - Redistribute IPSec\n                        subnets.\n                    - TIER0_NAT - Redistribute NAT IPs owned by\n                        Tier-0.\n                    - TIER0_EVPN_TEP_IP - Redistribute EVPN\n                        local endpoint subnets on Tier-0.\n                    - TIER1_NAT - Redistribute NAT IPs\n                        advertised by Tier-1 instances.\n                    - TIER1_LB_VIP - Redistribute LB VIP IPs\n                        advertised by Tier-1 instances.\n                    - TIER1_LB_SNAT - Redistribute LB SNAT IPs\n                        advertised by Tier-1 instances.\n                    - TIER1_DNS_FORWARDER_IP - Redistribute DNS\n                        forwarder subnets on Tier-1 instances.\n                    - TIER1_CONNECTED - Redistribute all\n                        subnets configured on Segments and\n                        Service Interfaces.\n                    - TIER1_SERVICE_INTERFACE - Redistribute\n                        Tier1 service interface subnets.\n                    - TIER1_SEGMENT - Redistribute subnets\n                        configured on Segments connected to\n                        Tier1.\n                    - TIER1_IPSEC_LOCAL_ENDPOINT - Redistribute\n                        IPSec VPN local-endpoint subnets\n                        advertised by TIER1.\n                type: list\n            route_redistribution_config:\n                description: Configure all route redistribution properties like\n                             enable/disable redistributon, redistribution rule\n                             and so on.\n                type: dict\n                suboptions:\n                    bgp_enabled:\n                        description: Flag to enable route redistribution.\n                        type: bool\n                        default: false\n                    redistribution_rules:\n                        description: List of redistribution rules.\n                        type: list\n                        elements: dict\n                        suboptions:\n                            name:\n                                description: Rule name\n                                type: str\n                            route_map_path:\n                                description: Route map to be associated with\n                                             the redistribution rule\n                                type: str\n                            route_redistribution_types:\n                                description: Tier-0 route redistribution types\n                                choices:\n                                    - TIER0_STATIC - Redistribute user added\n                                      static routes.\n                                    - TIER0_CONNECTED - Redistribute all\n                                      subnets configured on Interfaces and\n                                      routes related to TIER0_ROUTER_LINK,\n                                      TIER0_SEGMENT, TIER0_DNS_FORWARDER_IP,\n                                      TIER0_IPSEC_LOCAL_IP, TIER0_NAT types.\n                                    - TIER1_STATIC - Redistribute all subnets\n                                      and static routes advertised by Tier-1s.\n                                    - TIER0_EXTERNAL_INTERFACE - Redistribute\n                                      external interface subnets on Tier-0.\n                                    - TIER0_LOOPBACK_INTERFACE - Redistribute\n                                      loopback interface subnets on Tier-0.\n                                    - TIER0_SEGMENT - Redistribute subnets\n                                      configured on Segments connected to\n                                      Tier-0.\n                                    - TIER0_ROUTER_LINK - Redistribute router\n                                      link port subnets on Tier-0.\n                                    - TIER0_SERVICE_INTERFACE - Redistribute\n                                      Tier0 service interface subnets.\n                                    - TIER0_DNS_FORWARDER_IP - Redistribute DNS\n                                      forwarder subnets.\n                                    - TIER0_IPSEC_LOCAL_IP - Redistribute IPSec\n                                      subnets.\n                                    - TIER0_NAT - Redistribute NAT IPs owned by\n                                      Tier-0.\n                                    - TIER0_EVPN_TEP_IP - Redistribute EVPN\n                                      local endpoint subnets on Tier-0.\n                                    - TIER1_NAT - Redistribute NAT IPs\n                                      advertised by Tier-1 instances.\n                                    - TIER1_LB_VIP - Redistribute LB VIP IPs\n                                      advertised by Tier-1 instances.\n                                    - TIER1_LB_SNAT - Redistribute LB SNAT IPs\n                                      advertised by Tier-1 instances.\n                                    - TIER1_DNS_FORWARDER_IP - Redistribute DNS\n                                      forwarder subnets on Tier-1 instances.\n                                    - TIER1_CONNECTED - Redistribute all\n                                      subnets configured on Segments and\n                                      Service Interfaces.\n                                    - TIER1_SERVICE_INTERFACE - Redistribute\n                                      Tier1 service interface subnets.\n                                    - TIER1_SEGMENT - Redistribute subnets\n                                      configured on Segments connected to\n                                      Tier1.\n                                    - TIER1_IPSEC_LOCAL_ENDPOINT - Redistribute\n                                      IPSec VPN local-endpoint subnets\n                                      advertised by TIER1.\n                                type: list\n            ha_vip_configs:\n                type: list\n                elements: dict\n                description:\n                    - Array of HA VIP Config.\n                    - This configuration can be defined only for Active-Standby\n                      Tier0 gateway to provide redundancy. For mulitple\n                      external interfaces, multiple HA VIP configs must be\n                      defined and each config will pair exactly two external\n                      interfaces. The VIP will move and will always be owned by\n                      the Active node. When this property is configured,\n                      configuration of dynamic-routing is not allowed.\n                suboptions:\n                    enabled:\n                        description: Flag to enable this HA VIP config.\n                        default: true\n                        type: bool\n                    external_interface_paths:\n                        description:\n                            - Policy paths to Tier0 external interfaces for\n                              providing redundancy\n                            - Policy paths to Tier0 external interfaces which\n                              are to be paired to provide redundancy. Floating\n                              IP will be owned by one of these interfaces\n                              depending upon which edge node is Active.\n                        type: list\n                    vip_subnets:\n                        description:\n                            - VIP floating IP address subnets\n                            - Array of IP address subnets which will be used as\n                              floating IP addresses.\n                        type: list\n                        suboptions:\n                            ip_addresses:\n                                description: IP addresses assigned to interface\n                                type: list\n                                required: true\n                            prefix_len:\n                                description: Subnet prefix length\n                                type: int\n                                required: true\n            interfaces:\n                type: list\n                element: dict\n                description: Specify the interfaces associated with the Gateway\n                             in this section that need to be created, updated,\n                             or deleted\n                suboptions:\n                    id:\n                        description: Tier-1 Interface ID\n                        required: false\n                        type: str\n                    description:\n                        description: Tier-1 Interface  description\n                        type: str\n                    display_name:\n                        description:\n                            - Tier-1 Interface display name\n                            - Either this or id must be specified. If both are\n                              specified, id takes precedence.\n                        required: false\n                        type: str\n                    state:\n                        description:\n                            - State can be either 'present' or 'absent'.\n                              'present' is used to create or update resource.\n                              'absent' is used to delete resource.\n                            - Required if I(segp_id != null).\n                        choices:\n                            - present\n                            - absent\n                    tags:\n                        description: Opaque identifiers meaningful to the API\n                                     user\n                        type: dict\n                        suboptions:\n                            scope:\n                                description: Tag scope.\n                                required: true\n                                type: str\n                            tag:\n                                description: Tag value.\n                                required: true\n                                type: str\n                    achieve_subresource_state_if_del_parent:\n                        type: bool\n                        default: false\n                        description:\n                            - Can be used to achieve the state of subresources\n                              even if the parent(base) resource's state is\n                              absent.\n                            - Can be specified for each subresource.\n                    do_wait_till_create:\n                        type: bool\n                        default: false\n                        description:\n                            - Can be used to wait for the realization of\n                              subresource before the request to create the next\n                              resource is sent to the Manager\n                    ipv6_ndra_profile_id:\n                        description:\n                            - Configrue IPv6 NDRA profile. Only one NDRA\n                              profile can be configured\n                            - Required if I(id != null)\n                        type: str\n                    mtu:\n                        description:\n                            - MTU size\n                            - Maximum transmission unit (MTU) specifies the\n                              size of the largest packet that a network\n                              protocol can transmit.\n                        type: int\n                    segment_id:\n                        description:\n                            - Specify Segment to which this interface is\n                              connected to.\n                            - Required if I(id != null)\n                        type: str\n                    segment_display_name:\n                        description:\n                            - Same as segment_id\n                            - Either this or segment_id must be specified. If\n                              both are specified, segment_id takes precedence.\n                        type: str\n                    subnets:\n                        description:\n                            - IP address and subnet specification for interface\n                            - Specify IP address and network prefix for\n                              interface\n                            - Required if I(id != null)\n                        type: list\n                        elements: dict\n                        suboptions:\n                            ip_addresses:\n                                description: IP addresses assigned to interface\n                                type: str\n                            prefix_len:\n                                description: Subnet prefix length\n                                type: str\n                    urpf_mode:\n                        description: Unicast Reverse Path Forwarding mode\n                        type: str\n                        choices:\n                            - NONE\n                            - STRICT\n                        default: STRICT\n'''\n\nEXAMPLES = '''\n- name: create Tier1\n  nsxt_policy_tier1:\n    hostname: \"10.10.10.10\"\n    nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n    nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n    validate_certs: False\n    display_name: test-tier22222\n    state: present\n    failover_mode: \"PREEMPTIVE\"\n    disable_firewall: True\n    force_whitelisting: True\n    enable_standby_relocation: False\n    tags:\n      - scope: \"a\"\n        tag: \"b\"\n    route_advertisement_rules:\n      - name: \"test-route-advertisement-rules\"\n        route_advertisement_types: ['TIER1_STATIC_ROUTES', 'TIER1_CONNECTED']\n        subnets: [\"35.1.1.1/23\"]\n    route_advertisement_types:\n        - \"TIER1_STATIC_ROUTES\"\n        - \"TIER1_CONNECTED\"\n        - \"TIER1_NAT\"\n    tier0_display_name: \"node-t0\"\n    locale_services:\n      - state: present\n        display_name: test-t1ls-2\n        route_redistribution_config:\n          redistribution_rules:\n            - name: abc\n              route_redistribution_types: [\"TIER0_STATIC\", \"TIER0_NAT\"]\n        interfaces:\n          - id: \"test-t1-t1ls-iface-2\"\n            display_name: \"test-t1-t1ls-iface\"\n            state: present\n            subnets:\n              - ip_addresses: [\"35.1.1.1\"]\n                prefix_len: 24\n            segment_id: \"test-seg-2\"\n            ipv6_ndra_profile_id: test\n            mtu: 1400\n            urpf_mode: NONE\n'''\n\nRETURN = '''# '''\n\nimport json\nimport time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible.module_utils.basic import _ANSIBLE_ARGS as ANSIBLE_ARGS\nfrom ansible.module_utils._text import to_native\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_base_resource import NSXTBaseRealizableResource\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import (\n    TIER_0_URL, TIER_1_URL, IPV6_DAD_PROFILE_URL, IPV6_NDRA_PROFILE_URL,\n    DHCP_RELAY_CONFIG_URL, EDGE_CLUSTER_URL, EDGE_NODE_URL, SEGMENT_URL,\n    TIER_1_STATIC_ROUTE_URL, TIER_1_LOCALE_SERVICE_URL,\n    TIER_1_LS_INTERFACE_URL, TIER_0_LOCALE_SERVICE_URL,\n    TIER_0_LS_INTERFACE_URL)\n\n\nclass NSXTTier1(NSXTBaseRealizableResource):\n    @staticmethod\n    def get_resource_spec():\n        tier1_arg_spec = {}\n        tier1_arg_spec.update(\n            default_rule_logging=dict(\n                required=False,\n                type='bool'\n            ),\n            dhcp_config_id=dict(\n                required=False,\n                type='str'\n            ),\n            dhcp_config_display_name=dict(\n                required=False,\n                type='str'\n            ),\n            disable_firewall=dict(\n                required=False,\n                type='bool',\n                default=False\n            ),\n            enable_standby_relocation=dict(\n                required=False,\n                type='bool',\n                default=False\n            ),\n            failover_mode=dict(\n                required=False,\n                type='str',\n                default='NON_PREEMPTIVE',\n                choices=['NON_PREEMPTIVE', 'PREEMPTIVE']\n            ),\n            force_whitelisting=dict(\n                required=False,\n                type='bool',\n                default=False\n            ),\n            intersite_config=dict(\n                required=False,\n                type='dict',\n                options=dict(\n                    fallback_sites=dict(\n                        required=False,\n                        type='list'\n                    ),\n                    intersite_transit_subnet=dict(\n                        default=\"169.254.32.0/20\",\n                        type='str'\n                    ),\n                    last_admin_active_epoch=dict(\n                        required=False,\n                        type='int'\n                    ),\n                    primary_site_path=dict(\n                        required=False,\n                        type='str'\n                    ),\n                )\n            ),\n            ipv6_ndra_profile_id=dict(\n                required=False,\n                type='str'\n            ),\n            ipv6_ndra_profile_display_name=dict(\n                required=False,\n                type='str'\n            ),\n            ipv6_dad_profile_id=dict(\n                required=False,\n                type='str'\n            ),\n            ipv6_dad_profile_display_name=dict(\n                required=False,\n                type='str'\n            ),\n            pool_allocation=dict(\n                type='str',\n                choices=['ROUTING', 'LB_SMALL', 'LB_MEDIUM', 'LB_LARGE',\n                         'LB_XLARGE'],\n                default='ROUTING'\n            ),\n            qos_profile=dict(\n                type='dict',\n                options=dict(\n                    egress_qos_profile_path=dict(\n                        type='str'\n                    ),\n                    ingress_qos_profile_path=dict(\n                        type='str'\n                    )\n                )\n            ),\n            route_advertisement_rules=dict(\n                required=False,\n                type='list',\n                options=dict(\n                    action=dict(\n                        required=False,\n                        type='str',\n                        default='PERMIT',\n                        choices=['PERMIT', 'DENY']\n                    ),\n                    name=dict(\n                        required=True,\n                        type='str'\n                    ),\n                    prefix_operator=dict(\n                        required=False,\n                        type='str',\n                        default='GE',\n                        choices=['GE', 'EQ']\n                    ),\n                    route_advertisement_types=dict(\n                        required=False,\n                        type='list',\n                        choices=['TIER1_STATIC_ROUTES', 'TIER1_CONNECTED',\n                                 'TIER1_NAT', 'TIER1_LB_VIP', 'TIER1_LB_SNAT',\n                                 'TIER1_DNS_FORWARDER_IP',\n                                 'TIER1_IPSEC_LOCAL_ENDPOINT']\n                    ),\n                    subnets=dict(\n                        required=True,\n                        type='list'\n                    )\n                )\n            ),\n            route_advertisement_types=dict(\n                required=False,\n                type='list',\n                choices=['TIER1_STATIC_ROUTES', 'TIER1_CONNECTED', 'TIER1_NAT',\n                         'TIER1_LB_VIP', 'TIER1_LB_SNAT',\n                         'TIER1_DNS_FORWARDER_IP', 'TIER1_IPSEC_LOCAL_ENDPOINT'\n                         ]\n            ),\n            tier0_id=dict(\n                required=False,\n                type='str'\n            ),\n            tier0_display_name=dict(\n                required=False,\n                type='str'\n            )\n        )\n        return tier1_arg_spec\n\n    @staticmethod\n    def get_resource_base_url(baseline_args=None):\n        return TIER_1_URL\n\n    def update_resource_params(self, nsx_resource_params):\n        ipv6_profile_paths = []\n        if self.do_resource_params_have_attr_with_id_or_display_name(\n                \"ipv6_ndra_profile\"):\n            ipv6_ndra_profile_id = self.get_id_using_attr_name_else_fail(\n                    \"ipv6_ndra_profile\", nsx_resource_params,\n                    IPV6_NDRA_PROFILE_URL, \"Ipv6NdraProfile\")\n            ipv6_profile_paths.append(\n                IPV6_NDRA_PROFILE_URL + \"/\" + ipv6_ndra_profile_id)\n        if self.do_resource_params_have_attr_with_id_or_display_name(\n                \"ipv6_dad_profile\"):\n            ipv6_dad_profile_id = self.get_id_using_attr_name_else_fail(\n                    \"ipv6_dad_profile\", nsx_resource_params,\n                    IPV6_DAD_PROFILE_URL, \"Ipv6DadProfile\")\n            ipv6_profile_paths.append(\n                IPV6_DAD_PROFILE_URL + \"/\" + ipv6_dad_profile_id)\n        if ipv6_profile_paths:\n            nsx_resource_params[\"ipv6_profile_paths\"] = ipv6_profile_paths\n\n        if self.do_resource_params_have_attr_with_id_or_display_name(\n                \"dhcp_config\"):\n            dhcp_config_id = self.get_id_using_attr_name_else_fail(\n                \"dhcp_config\", nsx_resource_params,\n                DHCP_RELAY_CONFIG_URL, \"DhcpRelayConfig\")\n            nsx_resource_params[\"dhcp_config_paths\"] = [\n                DHCP_RELAY_CONFIG_URL + \"/\" + dhcp_config_id]\n\n        if self.do_resource_params_have_attr_with_id_or_display_name(\n                \"tier0\"):\n            tier0_id = self.get_id_using_attr_name_else_fail(\n                \"tier0\", nsx_resource_params,\n                TIER_0_URL, \"Tier0\")\n            nsx_resource_params[\"tier0_path\"] = (\n                TIER_0_URL + \"/\" + tier0_id)\n\n    def update_parent_info(self, parent_info):\n        parent_info[\"tier1_id\"] = self.id\n\n    class NSXTTier1StaticRoutes(NSXTBaseRealizableResource):\n        def get_spec_identifier(self):\n            return NSXTTier1.NSXTTier1StaticRoutes.get_spec_identifier()\n\n        @classmethod\n        def get_spec_identifier(cls):\n            return \"static_routes\"\n\n        @staticmethod\n        def get_resource_spec():\n            tier1_sr_arg_spec = {}\n            tier1_sr_arg_spec.update(\n                network=dict(\n                    required=True,\n                    type='str'\n                ),\n                next_hops=dict(\n                    required=True,\n                    type='list',\n                    elements='dict',\n                    options=dict(\n                        admin_distance=dict(\n                            type='int',\n                            default=1\n                        ),\n                        ip_address=dict(\n                            type='str'\n                        ),\n                        scope=dict(\n                            type='list',\n                            elements='str'\n                        )\n                    )\n                ),\n            )\n            return tier1_sr_arg_spec\n\n        @staticmethod\n        def get_resource_base_url(parent_info):\n            tier1_id = parent_info.get(\"tier1_id\", 'default')\n            return TIER_1_STATIC_ROUTE_URL.format(tier1_id)\n\n    class NSXTTier1LocaleService(NSXTBaseRealizableResource):\n        def get_spec_identifier(self):\n            return NSXTTier1.NSXTTier1LocaleService.get_spec_identifier()\n\n        @classmethod\n        def get_spec_identifier(cls):\n            return \"locale_services\"\n\n        def infer_resource_id(self, parent_info):\n            all_locale_services = self.get_all_resources_from_nsx()\n            if len(all_locale_services) == 0:\n                self.module.fail_json(\n                    msg=\"No {} found under Tier1 gateway {}. Please specify \"\n                        \"the id or display_name of the LocaleService to be \"\n                        \"created\".format(\n                            self.get_spec_identifier(),\n                            parent_info.get(\"tier1_id\", 'default')))\n            if len(all_locale_services) > 1:\n                ls_ids = [ls['id'] for ls in all_locale_services]\n                self.module.fail_json(\n                    msg=\"Multiple {} found under Tier1 gateway {} with IDs \"\n                        \"{}. Please specify the id of the LocaleService \"\n                        \"to be updated\".format(\n                            self.get_spec_identifier(),\n                            parent_info.get(\"tier1_id\", 'default'), ls_ids))\n            return all_locale_services[0]['id']\n\n        @staticmethod\n        def get_resource_spec():\n            tier1_ls_arg_spec = {}\n            tier1_ls_arg_spec.update(\n                edge_cluster_info=dict(\n                    required=False,\n                    type='dict',\n                    options=dict(\n                        # Note that only default site_id and\n                        # enforcementpoint_id are used\n                        site_id=dict(\n                            type='str',\n                            default=\"default\"\n                        ),\n                        enforcementpoint_id=dict(\n                            type='str',\n                            default=\"default\"\n                        ),\n                        edge_cluster_id=dict(\n                            type='str'\n                        ),\n                        edge_cluster_display_name=dict(\n                            type='str'\n                        )\n                    )\n                ),\n                preferred_edge_nodes_info=dict(\n                    required=False,\n                    type='list',\n                    options=dict(\n                        # Note that only default site_id and\n                        # enforcementpoint_id are used\n                        site_id=dict(\n                            type='str',\n                            default=\"default\"\n                        ),\n                        enforcementpoint_id=dict(\n                            type='str',\n                            default=\"default\"\n                        ),\n                        edge_cluster_id=dict(\n                            type='str'\n                        ),\n                        edge_cluster_display_name=dict(\n                            type='str'\n                        ),\n                        edge_node_id=dict(\n                            type='str'\n                        ),\n                        edge_node_display_name=dict(\n                            type='str'\n                        )\n                    )\n                ),\n                route_redistribution_types=dict(\n                    required=False,\n                    type='list',\n                    elements='str',\n                ),\n                route_redistribution_config=dict(\n                    type='dict',\n                    required=False,\n                    options=dict(\n                        bgp_enabled=dict(\n                            type='bool',\n                            default=False\n                        ),\n                        redistribution_rules=dict(\n                            type='list',\n                            required=False,\n                            elements='dict',\n                            options=dict(\n                                name=dict(\n                                    type='str',\n                                    required=False\n                                ),\n                                route_map_path=dict(\n                                    type='str',\n                                    required=False\n                                ),\n                                route_redistribution_types=dict(\n                                    type='list',\n                                    elements='str',\n                                    required=False\n                                ),\n                            )\n                        )\n                    )\n                ),\n                ha_vip_configs=dict(\n                    type='list',\n                    elements='dict',\n                    options=dict(\n                        enabled=dict(\n                            default=True,\n                            type='bool'\n                        ),\n                        external_interface_info=dict(\n                            required=True,\n                            type='list',\n                            elements='dict',\n                            options=dict(\n                                tier0_id=dict(\n                                    type='str',\n                                ),\n                                tier0_display_name=dict(\n                                    type='str',\n                                ),\n                                tier0_ls_id=dict(\n                                    type='str',\n                                ),\n                                tier0_ls_display_name=dict(\n                                    type='str',\n                                ),\n                                tier0_ls_interface_id=dict(\n                                    type='str',\n                                ),\n                                tier0_ls_interface_display_name=dict(\n                                    type='str',\n                                ),\n                                external_interface_path=dict(\n                                    type='str'\n                                )\n                            )\n                        ),\n                        vip_subnets=dict(\n                            type='list',\n                            elements='dict',\n                            required=True,\n                            options=dict(\n                                ip_addresses=dict(\n                                    type='list',\n                                    required=True\n                                ),\n                                prefix_len=dict(\n                                    type='int',\n                                    rqeuired=True\n                                )\n                            )\n                        ),\n                    )\n                )\n            )\n            return tier1_ls_arg_spec\n\n        @staticmethod\n        def get_resource_base_url(parent_info):\n            tier1_id = parent_info.get(\"tier1_id\", 'default')\n            return TIER_1_LOCALE_SERVICE_URL.format(tier1_id)\n\n        def update_resource_params(self, nsx_resource_params):\n            if \"edge_cluster_info\" in nsx_resource_params:\n                edge_cluster_info = nsx_resource_params.pop(\n                    \"edge_cluster_info\")\n                site_id = edge_cluster_info[\"site_id\"]\n                enforcementpoint_id = edge_cluster_info[\"enforcementpoint_id\"]\n                edge_cluster_base_url = (\n                    EDGE_CLUSTER_URL.format(site_id, enforcementpoint_id))\n                edge_cluster_id = self.get_id_using_attr_name_else_fail(\n                    \"edge_cluster\", edge_cluster_info, edge_cluster_base_url,\n                    \"Edge Cluster\")\n                nsx_resource_params[\"edge_cluster_path\"] = (\n                    edge_cluster_base_url + \"/\" + edge_cluster_id)\n\n            if \"preferred_edge_nodes_info\" in nsx_resource_params:\n                preferred_edge_nodes_info = nsx_resource_params.pop(\n                    \"preferred_edge_nodes_info\")\n                nsx_resource_params[\"preferred_edge_paths\"] = []\n                for preferred_edge_node_info in preferred_edge_nodes_info:\n                    site_id = preferred_edge_node_info.get(\n                        \"site_id\", \"default\")\n                    enforcementpoint_id = preferred_edge_node_info.get(\n                        \"enforcementpoint_id\", \"default\")\n                    edge_cluster_base_url = (\n                        EDGE_CLUSTER_URL.format(site_id, enforcementpoint_id))\n                    edge_cluster_id = self.get_id_using_attr_name_else_fail(\n                        \"edge_cluster\", preferred_edge_node_info,\n                        edge_cluster_base_url, 'Edge Cluster')\n                    edge_node_base_url = EDGE_NODE_URL.format(\n                        site_id, enforcementpoint_id, edge_cluster_id)\n                    edge_node_id = self.get_id_using_attr_name_else_fail(\n                        \"edge_node\", preferred_edge_node_info,\n                        edge_node_base_url, \"Edge Node\")\n                    nsx_resource_params[\"preferred_edge_paths\"].append(\n                        edge_node_base_url + \"/\" + edge_node_id)\n\n            if 'ha_vip_configs' in nsx_resource_params:\n                for ha_vip_config in nsx_resource_params['ha_vip_configs']:\n                    external_interface_info = ha_vip_config.pop(\n                        'external_interface_info')\n                    external_interface_paths = []\n                    for external_interface in (\n                            external_interface_info):\n                        external_interface_path = external_interface.get(\n                            'external_interface_path')\n                        if not external_interface_path:\n                            tier0_id = self.get_id_using_attr_name_else_fail(\n                                'tier0', external_interface, TIER_0_URL,\n                                \"Tier 0\")\n                            tier0_ls_id = (\n                                self.get_id_using_attr_name_else_fail(\n                                    'tier0_ls', external_interface,\n                                    TIER_0_LOCALE_SERVICE_URL,\n                                    \"Tier 0 Locale Service\"))\n                            tier0_ls_inf_id = (\n                                self.get_id_using_attr_name_else_fail(\n                                    'tier0_ls_interface', external_interface,\n                                    TIER_0_LS_INTERFACE_URL,\n                                    \"Tier 0 Interface\"))\n                            external_interface_path = (\n                                TIER_0_LS_INTERFACE_URL.format(\n                                    tier0_id, tier0_ls_id) + \"/\" +\n                                tier0_ls_inf_id)\n                        external_interface_paths.append(\n                            external_interface_path)\n                    ha_vip_config[\n                        'external_interface_paths'] = external_interface_paths\n\n        def update_parent_info(self, parent_info):\n            parent_info[\"ls_id\"] = self.id\n\n        class NSXTTier1Interface(NSXTBaseRealizableResource):\n            def get_spec_identifier(self):\n                return (NSXTTier1.NSXTTier1LocaleService.NSXTTier1Interface\n                        .get_spec_identifier())\n\n            @classmethod\n            def get_spec_identifier(cls):\n                return \"interfaces\"\n\n            @staticmethod\n            def get_resource_spec():\n                tier1_ls_int_arg_spec = {}\n                tier1_ls_int_arg_spec.update(\n                    ipv6_ndra_profile_id=dict(\n                        required=False,\n                        type='str'\n                    ),\n                    mtu=dict(\n                        type='int'\n                    ),\n                    segment_id=dict(\n                        required=False,\n                        type='str'\n                    ),\n                    segment_display_name=dict(\n                        required=False,\n                        type='str'\n                    ),\n                    subnets=dict(\n                        required=True,\n                        type='list',\n                        elements='dict',\n                        options=dict(\n                            ip_addresses=dict(\n                                type='list',\n                                elements='str'\n                            ),\n                            prefix_len=dict(\n                                type='int'\n                            )\n                        )\n                    ),\n                    urpf_mode=dict(\n                        type='str',\n                        default='STRICT',\n                        choices=['NONE', 'STRICT']\n                    )\n                )\n                return tier1_ls_int_arg_spec\n\n            @staticmethod\n            def get_resource_base_url(parent_info):\n                tier1_id = parent_info.get(\"tier1_id\", 'default')\n                locale_service_id = parent_info.get(\"ls_id\", 'default')\n                return TIER_1_LS_INTERFACE_URL.format(\n                    tier1_id, locale_service_id)\n\n            def update_resource_params(self, nsx_resource_params):\n                # segment_id is a required attr\n                segment_id = self.get_id_using_attr_name_else_fail(\n                    \"segment\", nsx_resource_params, SEGMENT_URL, \"Segment\")\n                nsx_resource_params[\"segment_path\"] = (\n                    SEGMENT_URL + \"/\" + segment_id)\n\n                if self.do_resource_params_have_attr_with_id_or_display_name(\n                        \"ipv6_ndra_profile\"):\n                    ipv6_ndra_profile_id = (\n                        self.get_id_using_attr_name_else_fail(\n                            \"ipv6_ndra_profile\", nsx_resource_params,\n                            IPV6_NDRA_PROFILE_URL, \"Ipv6 NDRA Profile\"))\n                    nsx_resource_params[\"ipv6_profile_paths\"] = [\n                        IPV6_NDRA_PROFILE_URL + \"/\" + ipv6_ndra_profile_id]\n\n\nif __name__ == '__main__':\n    nsxt_tier1 = NSXTTier1()\n    nsxt_tier1.realize()\n"
  },
  {
    "path": "plugins/modules/nsxt_principal_identities.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_principal_identities\nshort_description: 'Register a name-certificate combination.'\ndescription: \"Associates a principal's name with a certificate that is used to authenticate. \"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    display_name:\n        description: 'Identifier to use when displaying entity in logs or GUI'\n        required: true\n        type: str\n    name:\n        description: 'Name of the principal'\n        required: true\n        type: str\n    node_id:\n        description: 'Unique node-id'\n        required: true\n        type: str\n    certificate_name:\n        description: 'Display name of the certificate attached'\n        required: true\n        type: str\n    role:\n        description: 'Role'\n        required: true\n        type: str\n    description:\n        description: 'Description of this resource'\n        required: false\n        type: str\n    resource_type:\n        description: 'Must be set to the value PrincipalIdentity'\n        required: false\n        type: str\n    id:\n        description: 'Unique identifier of this resource'\n        required: false\n        type: str\n    is_protected:\n        description: 'Description of this resource'\n        required: false\n        type: bool\n    tags:\n        description: Opaque identifier meaninful to API user\n        required: false\n        type: Array of Tag\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n'''\n\nEXAMPLES = '''\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Register a name-certificate combination\n      nsxt_principal_identities:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"Akhilesh_principal_display_name\"\n        name: \"Akhilesh_principal_name\"\n        node_id: \"node-1\"\n        role: \"enterprise_admin\"\n        certificate_name: \"Akhilesh_cert\"\n        state: \"present\"\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request, get_certificate_string\nfrom ansible.module_utils._text import to_native\n\ndef get_principal_identity_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_principal_identity_update_params(args=None):\n    args_to_remove = ['name', 'node_id', 'certificate_pem', 'role', 'is_protected']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef update_params_with_pem_encoding(principal_id_params):\n    '''\n    params: Parameters passed to the certificate\n    result: Updated parameters. Files are replaced with the public and private strings. \n    '''\n    principal_id_params['certificate_pem'] = get_certificate_string (principal_id_params.pop('certificate_pem_file', None))\n    return principal_id_params\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, principal_id_params ):\n    principal_id_params['certificate_id'] = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                            '/trust-management/certificates', principal_id_params.pop('certificate_name', None))\n    return principal_id_params\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name):\n  try:\n    (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n  for result in resp['results']:\n    if result.__contains__('display_name') and result['display_name'] == display_name:\n      return result['id']\n  module.fail_json(msg='No id exists with display name %s' % display_name)\n\ndef get_principal_ids(module, manager_url, mgr_username, mgr_password, validate_certs):\n  try:\n    (rc, resp) = request(manager_url+ '/trust-management/principal-identities', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing principal identities. Error [%s]' % (to_native(err)))\n  return resp\n\ndef get_principal_id_with_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n  '''\n  result: returns the principal id of the display name provided\n  '''\n  principal_ids = get_principal_ids(module, manager_url, mgr_username, mgr_password, validate_certs)\n  if principal_ids and len(principal_ids['results'])>0:\n    for principal_id in principal_ids['results']:\n      if principal_id.__contains__('display_name') and principal_id['display_name'] == display_name:\n        return principal_id\n  return None\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, display_name, principal_id_params):\n  '''\n      Checks if principal identity exists, if exists it means we need to update already existing\n      principal identity after checking if there are any differences with respect to existing\n      display name\n  '''\n  existing_principal_id = get_principal_id_with_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  if existing_principal_id is None:\n    return False\n  if not existing_principal_id.__contains__('description') and principal_id_params.__contains__('description'):\n    return True\n  if existing_principal_id.__contains__('description') and not principal_id_params.__contains__('description'):\n    return True\n  if existing_principal_id.__contains__('description') and principal_id_params.__contains__('description') and\\\n  existing_principal_id['description'] != principal_id_params['description']:\n    return True\n  if existing_principal_id.__contains__('certificate_id') and principal_id_params.__contains__('certificate_id') and\\\n  existing_principal_id['certificate_id'] != principal_id_params['certificate_id']:\n    return True\n  return False\n\ndef get_certificate_id_with_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n  '''\n  result: returns the certificate object with the display name provided\n  '''\n  certificates = get_certificates(module, manager_url, mgr_username, mgr_password, validate_certs)\n  if certificates and certificates['result_count']>0:\n    for certificate in certificates['results']:\n      if certificate.__contains__('display_name') and certificate['display_name'] == display_name:\n        return certificate['id']\n  return None\n\ndef main():\n  argument_spec = dict()\n  argument_spec.update(hostname=dict(type='str', required=True),\n                       username=dict(type='str', required=True),\n                       password=dict(type='str', required=True, no_log=True),\n                       port=dict(type='int', default=443),\n                       validate_certs=dict(type='bool', requried=False, default=True),\n                       display_name=dict(required=True, type='str'),\n                       name=dict(required=True, type='str'), \n                       node_id=dict(required=True, type='str'),\n                       certificate_name=dict(required=False, type='str'),\n                       certificate_pem_file=dict(required=True, type='str', no_log=True),\n                       role=dict(required=False, type='str'),\n                       description=dict(required=False, type='str'),\n                       resource_type=dict(required=False, type='str'),\n                       id=dict(required=False, type='str'),\n                       is_protected=dict(required=False, type='bool'),\n                       tags=dict(required=False, type='list'),\n                    state=dict(required=True, choices=['present', 'absent']))\n  '''\n  Core function of the module reponsible for adding and deleting the certififcate.\n  '''\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  principal_id_params = get_principal_identity_params(module.params.copy())\n  principal_id_params = update_params_with_pem_encoding(principal_id_params)\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n  if principal_id_params.__contains__('certificate_name'):\n    principal_id_params = update_params_with_id(module, manager_url, mgr_username, mgr_password, validate_certs, principal_id_params)\n  principal_id_with_display_name = get_principal_id_with_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n\n  if state == 'present':\n    # update the principal identity\n    if check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, display_name, principal_id_params):\n      if principal_id_with_display_name:\n        principal_id_params['principal_identity_id'] = principal_id_with_display_name['id']\n        principal_id_params = get_principal_identity_update_params(principal_id_params.copy())\n        request_data = json.dumps(principal_id_params)\n        try:\n          (rc, resp) = request(manager_url+ '/trust-management/principal-identities?action=update_certificate', data=request_data, headers=headers, method='POST',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n        except Exception as err:\n          module.fail_json(msg=\"Failed to update principal identity. Error[%s]. Request body [%s].\" % (request_data, to_native(err)))\n        time.sleep(5)\n        module.exit_json(changed=True, result=resp, message=\"Principal identity updated.\")\n    # add the principal identity\n    if principal_id_with_display_name:\n      module.exit_json(changed=False, msg=\"Principal id with display name \\'%s\\' already exists.\" % display_name) \n    request_data = json.dumps(principal_id_params)\n    try:\n        (rc, resp) = request(manager_url+ '/trust-management/principal-identities/with-certificate', data=request_data, headers=headers, method='POST',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to add principal identity. Error[%s]. Request body [%s].\" % (request_data, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, result=resp, message=\"Principal identity created.\")\n\n  elif state == 'absent':\n    # delete the principal identity\n    if not principal_id_with_display_name:\n      module.fail_json(msg=\"Principal identity with display name \\'%s\\' doesn't exists.\" % display_name)\n    principal_id = principal_id_with_display_name['id']\n    try:\n       (rc, resp) = request(manager_url+ '/trust-management/principal-identities/' + principal_id, method='DELETE',\n                            url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg=\"Failed to delete principal identity with display name \\'%s\\'. Error[%s].\" % (display_name, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=principal_id, message=\"Principal identity with display name \\'%s\\' and principal id \\'%s\\' deleted.\" %(display_name, principal_id))\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_principal_identities_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_principal_identities_facts\nshort_description: List all existing principal identities\ndescription: Returns the list of principals registered with a certificate.\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n\n'''\n\nEXAMPLES = '''\n- name: List all existing certificates\n  nsxt_principal_identities_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/trust-management/principal-identities', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing transport zone. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_repo_sync.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_repo_sync\nshort_description: 'Synchronizes the repository data between nsx managers'\ndescription: \"Attempts to synchronize the repository partition on nsx \n              manager. Repository partition contains packages required for \n              the install and upgrade of nsx components.Normally \n              there is no need to call this API explicitely by the user.\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: Synchronizes the repository data between nsx managers\n  nsxt_repo_sync:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n \n  # Synchronize the repository data between nsx managers\n\n  if module.check_mode:\n    module.exit_json(changed=False, debug_out='The repository data between NSX'\n                     ' managers will be synchronized.', id=mgr_hostname)\n  try:\n    (rc, resp) = request(manager_url+ '/cluster/node?action=repo_sync', data='',\n                         headers=headers, method='POST', url_username=mgr_username,\n                         url_password=mgr_password, validate_certs=validate_certs,\n                         ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Failed to synchronize repositories of NSX '\n                          'managers. Error[%s].' % to_native(err))\n\n  time.sleep(5)\n  module.exit_json(changed=True, result=resp, message='NSX Manager repositories'\n                                                      ' synchronization started.')\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_repo_sync_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_repo_sync_facts\nshort_description: 'Get synchronize status of a manager node'\ndescription: \"Returns the synchronization status for the manager represented by given .\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    node_name:\n        description: 'Name of auto-deployment node'\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: Get repo sync status of an auto deployed node\n  nsxt_repo_sync_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      node_name: \"Manager-01\"\n      state: present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import get_id_from_display_name_results\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(node_name=dict(required=True, type='str'))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  manager_node_name = module.params['node_name']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  manager_node_id = get_id_from_display_name_results(module, manager_url, \n    '/cluster/nodes/deployments', mgr_username, mgr_password, validate_certs,\n    ['deployment_config','hostname'], ['vm_id'], manager_node_name)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url + '/cluster/nodes/%s/repo_sync/status' % manager_node_id,\n                         headers=dict(Accept='application/json'), url_username=mgr_username,\n                         url_password=mgr_password, validate_certs=validate_certs,\n                         ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing manager node repo sync '\n                                  'status. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_rest.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# Copyright: (c) 2020, sky-joker\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {\n    'metadata_version': '1.1',\n    'status': ['preview'],\n    'supported_by': 'community'\n}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_rest\nshort_description: Direct access to the NSX REST API\ndescription:\n    - Provides direct access to the NSX REST API to execute the API.\nauthor:\n    - sky-joker (@sky-joker)\nrequirements:\n    - \"python >= 2.7\"\noptions:\n    hostname:\n        description: \"Deployed NSX manager hostname.\"\n        required: true\n        type: str\n    username:\n        description: \"The username to authenticate with the NSX manager.\"\n        required: true\n        type: str\n    password:\n        description: \"The password to authenticate with the NSX manager.\"\n        required: true\n        type: str\n    path:\n        description: \"URI being used to execute API calls.\"\n        required: true\n        type: str\n    method:\n        description:\n            - \"The HTTP method of the request.\"\n        required: false\n        choices:\n            - get\n            - post\n            - put\n            - patch\n            - delete\n        default: get\n        type: str\n    src:\n        description:\n            - \"The absolute path to the file containing the request body(payload) to be sent to the NSX REST API.\"\n            - \"If this option isn't used, use the C(content) option instead.\"\n            - \"If this option is used, the C(content) option is ignored.\"\n        required: false\n        type: str\n    content:\n        description:\n            - \"The request body(payload) to be sent to the NSX REST API.\"\n            - \"If this option isn't used, use the C(src) option instead.\"\n        required: false\n        type: raw\n'''\n\nEXAMPLES = '''\n- name: create a new segment\n  nsxt_rest:\n    hostname: \"{{ nsxt_hostname }}\"\n    username: \"{{ nsxt_username }}\"\n    password: \"{{ nsxt_password }}\"\n    validate_certs: false\n    method: patch\n    path: /policy/api/v1/infra/segments/segment\n    content:\n      {\n        \"display_name\": \"segment\",\n        \"subnets\": [\n          {\n            \"gateway_address\": \"192.168.0.1/24\"\n          }\n        ],\n      }\n\n- name: get segment information\n  nsxt_rest:\n    hostname: \"{{ nsxt_hostname }}\"\n    username: \"{{ nsxt_username }}\"\n    password: \"{{ nsxt_password }}\"\n    validate_certs: false\n    method: get\n    path: /policy/api/v1/infra/segments/segment\n  register: get_segment_information_result\n\n- name: delete a segment\n  nsxt_rest:\n    hostname: \"{{ nsxt_hostname }}\"\n    username: \"{{ nsxt_username }}\"\n    password: \"{{ nsxt_password }}\"\n    validate_certs: false\n    method: delete\n    path: /policy/api/v1/infra/segments/segment\n'''\n\nRETURN = '''\nbody:\n    description: dictionary of requested result information\n    returned: always\n    type: dict\n    sample:\n      {\n          \"_create_time\": 1588405512111,\n          \"_create_user\": \"admin\",\n          \"_last_modified_time\": 1588405613884,\n          \"_last_modified_user\": \"admin\",\n          \"_protection\": \"NOT_PROTECTED\",\n          \"_revision\": 1,\n          \"_system_owned\": false,\n          \"admin_state\": \"UP\",\n          \"display_name\": \"segment\",\n          \"id\": \"segment\",\n          \"marked_for_delete\": false,\n          \"overridden\": false,\n          \"parent_path\": \"/infra\",\n          \"path\": \"/infra/segments/segment\",\n          \"relative_path\": \"segment\",\n          \"replication_mode\": \"MTEP\",\n          \"resource_type\": \"Segment\",\n          \"subnets\": [\n              {\n                  \"gateway_address\": \"192.168.0.1/24\",\n                  \"network\": \"192.168.0.0/24\"\n              }\n          ],\n          \"type\": \"DISCONNECTED\",\n          \"unique_id\": \"0361313c-20f0-42ba-aa77-e090277a50ac\"\n      }\n'''\n\n\nimport os\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec\nfrom ansible.module_utils.urls import basic_auth_header, fetch_url\n\n\nclass VMwareNSXTRest():\n    def __init__(self, module):\n        self.module = module\n        self.mgr_hostname = module.params[\"hostname\"]\n        self.mgr_username = module.params[\"username\"]\n        self.mgr_password = module.params[\"password\"]\n        self.path = module.params[\"path\"]\n        self.method = module.params[\"method\"]\n        self.src = module.params[\"src\"]\n        self.content = module.params[\"content\"]\n\n        self.manager_url = \"https://{}\".format(self.mgr_hostname)\n        self.headers = {\n            \"authorization\": basic_auth_header(self.mgr_username, self.mgr_password),\n            \"Accept\": \"application/json\",\n            \"Content-Type\": \"application/json\"\n        }\n\n        if self.src:\n            if os.path.isfile(self.src):\n                try:\n                    with open(self.src, \"r\") as f:\n                        self.content = json.loads(f.read())\n                except Exception as err:\n                    self.module.fail_json(msg=\"src read error: %s\" % err)\n            else:\n                self.module.fail_json(msg=\"cannot find/access src '%s'\" % self.src)\n\n    def error_code_check(self, info):\n        status = info.get('status')\n        if status >= 400:\n            self.module.fail_json(msg=\"error_code: %s, error_message: %s\"\n                                      % (status, json.loads(info.get('body'))['error_message']))\n\n        if status == -1:\n            self.module.fail_json(msg=\"error_code: %s, error_message: %s\" % (status, info.get('msg')))\n\n    def operate_nsxt(self, method, ignore_errors=False):\n        try:\n            (resp, info) = fetch_url(self.module, self.manager_url + self.path, method=method.upper(), headers=self.headers,\n                                     data=json.dumps(self.content))\n        except Exception as err:\n            self.module.fail_json(msg=\"nsxt rest api request error: %s, error url: %s\"\n                                      % (err, self.manager_url + self.path))\n\n        if ignore_errors is False:\n            self.error_code_check(info)\n\n        resp_body = resp.read() if 'read' in dir(resp) else False\n        if resp_body:\n            return json.loads(resp_body)\n        else:\n            return \"\"\n\n    def execute(self):\n        if self.method == \"get\":\n            resp = self.operate_nsxt(method=self.method)\n            self.module.exit_json(changed=False, body=resp)\n\n        if self.method == \"post\" or self.method == \"put\" or self.method == \"patch\":\n            before_resp = self.operate_nsxt(method=\"get\", ignore_errors=True)\n            if before_resp:\n                before_revision = before_resp[\"_revision\"]\n            else:\n                before_revision = \"\"\n\n            _ = self.operate_nsxt(method=self.method)\n\n            after_resp = self.operate_nsxt(method=\"get\")\n            after_revision = after_resp[\"_revision\"]\n\n            if before_revision == after_revision:\n                self.module.exit_json(changed=False, body=after_resp)\n            else:\n                self.module.exit_json(changed=True, body=after_resp)\n\n        if self.method == \"delete\":\n            resp = self.operate_nsxt(method=\"get\", ignore_errors=True)\n            if resp:\n                resp = self.operate_nsxt(method=self.method)\n                self.module.exit_json(changed=True, body=resp)\n            else:\n                self.module.exit_json(changed=False, body=resp)\n\n\ndef main():\n    argument_spec = vmware_argument_spec()\n    argument_spec.update(path=dict(type='str', required=True),\n                         method=dict(type='str', choices=['get', 'post', 'put', 'patch', 'delete'], default='get'),\n                         src=dict(type='str'),\n                         content=dict(type='raw'),)\n\n    module = AnsibleModule(argument_spec, supports_check_mode=True)\n\n    vmware_nsx_rest = VMwareNSXTRest(module)\n    vmware_nsx_rest.execute()\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_route_advertise.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': 'xx',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\nDOCUMENTATION = '''\n---\nmodule: nsxt_route_advertise\nshort_description: 'Toggle tier 1 route advertisement'\ndescription: \"Toggle route advertisement on Tier 1 routers\"\n\nversion_added: '2.7'\nauthor: 'Matt Proud'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    display_name:\n        description: 'Display name of Tier 1 router'\n        required: true\n        type: str\n    enabled:\n        description: 'Flag to enable this configuration'\n        type: boolean\n        required: false\n    advertise_static_routes:\n        description: 'Flag to advertise all static routes'\n        required: false\n        type: boolean\n    advertise_dns_forwarder:\n        description: 'Flag to advertise all routes of dns forwarder listener ips and source ips'\n        required: false\n        type: boolean\n    advertise_lb_snat_ip:\n        description: 'Flag to advertise all lb SNAT ips'\n        required: false\n        type: boolean\n    advertise_lb_vip:\n        description: 'Flag to advertise lb vips'\n        required: false\n        type: boolean\n    advertise_nat_routes:\n        description: 'Flag to advertise all routes of nat'\n        required: false\n        type: boolean\n    advertise_nsx_connected_routes:\n        description: 'Flag to advertise all connected routes'\n        required: false\n        type: boolean\n    \n'''\n\nEXAMPLES = '''\n- name: Toggle tier 1 route advertisement\n  nsxt_route_advertise:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    enabled: True\n    advertise_static_routes: True\n    advertise_dns_forwarder: True\n    advertise_lb_snat_ip: True\n    advertise_lb_vip: True\n    advertise_nat_routes: True\n    advertise_nsx_connected_routes: True\n'''\n\nRETURN = '''# '''\n\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef get_advertise_params(args=None):\n    args_to_remove = ['username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_logical_routers(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/logical-routers', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing logical routers. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_lr_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    logical_routers = get_logical_routers(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for logical_router in logical_routers['results']:\n        if logical_router.__contains__('display_name') and logical_router['display_name'] == display_name:\n            return logical_router\n    return None\n\ndef get_revision(module, manager_url, mgr_username, mgr_password, validate_certs, logical_router_id):\n  try:\n    (rc, resp) = request(manager_url+ '/logical-routers/%s/routing/advertisement' % logical_router_id, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    return resp['_revision']\n  except Exception as err:\n    module.fail_json(msg='Error accessing current advertisement. Error [%s]' % (to_native(err)))\n    \n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                        enabled=dict(required=False, type='bool'),\n                        advertise_static_routes=dict(required=False, type='bool'),\n                        advertise_dns_forwarder=dict(required=False, type='bool'),\n                        advertise_lb_snat_ip=dict(required=False, type='bool'),\n                        advertise_lb_vip=dict(required=False, type='bool'),\n                        advertise_nat_routes=dict(required=False, type='bool'),\n                        advertise_nsx_connected_routes=dict(required=False, type='bool')\n                        )\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  advertise_params = get_advertise_params(module.params.copy())\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  logical_router_dict = get_lr_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  logical_router_id = None\n  if logical_router_dict:\n    logical_router_id = logical_router_dict['id']\n  \n  advertise_params['_revision'] = get_revision(module, manager_url, mgr_username, mgr_password, \n                                              validate_certs, logical_router_id) # update current revision\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n   \n  # add the pool\n  if module.check_mode:\n    module.exit_json(changed=True, debug_out=str(json.dumps(advertise_params)), id='12345')\n  request_data = json.dumps(advertise_params)\n  try:\n    (rc, resp) = request(manager_url+ '/logical-routers/%s/routing/advertisement' % logical_router_id, data=request_data, headers=headers, method='PUT',\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n      module.fail_json(msg=\"Failed to toggle config. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n  time.sleep(5)\n  module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"Router advertisement set for display name %s.\" % module.params['display_name'])\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_transport_node_collections.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_transport_node_collections\nshort_description: Create transport node collection by attaching Transport Node Profile to cluster.\ndescription: \"When transport node collection is created the hosts which are part\nof compute collection will be prepared automatically i.e. NSX Manager\nattempts to install the NSX components on hosts. Transport nodes for these\nhosts are created using the configuration specified in transport node\nprofile.\"\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n    cluster_name:\n        description: CLuster Name\n        required: false\n        type: str\n    compute_manager_name:\n        description: Cluster Manager Name\n        required: false\n        type: str\n    description:\n        description: Description\n        required: true\n        type: str\n    display_name:\n        description: Display name\n        required: true\n        type: str\n    resource_type:\n        description: \"Must be set to the value TransportNodeCollection\"\n        required: true\n        type: str\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'. \n                     'present' is used to create or update resource. \n                     'absent' is used to delete resource.\"\n        required: true\n    transport_node_profile_name:\n        description: Transport Node Profile Names\n        required: true\n        type: str\n    \n'''\n\nEXAMPLES = '''\n- name: Create transport node collection\n    nsxt_transport_node_collections:\n      hostname: \"{{hostname}}\"\n      username: \"{{username}}\"\n      password: \"{{password}}\"\n      validate_certs: False\n      display_name: \"TNC1\"\n      resource_type: \"TransportNodeCollection\"\n      description: \"Transport Node Collections 1\"\n      compute_manager_name: \"VC1\"\n      cluster_name: \"cl1\"\n      transport_node_profile_name: \"TNP1\"\n      state: present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\nimport ssl\nimport socket\nimport hashlib\n\ndef get_transport_node_collections_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_transport_node_collections(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/transport-node-collections', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing transport-node-collections. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name, exit_if_not_found=True):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['id']\n    if exit_if_not_found:\n        module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef get_transport_node_collection_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    transport_node_collections = get_transport_node_collections(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for transport_node_collection in transport_node_collections['results']:\n        if transport_node_collection.__contains__('display_name') and transport_node_collection['display_name'] == display_name:\n            return transport_node_collection\n    return None\n\ndef wait_till_delete(id, module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      while True:\n          (rc, resp) = request(manager_url+ '/transport-node-collections/%s'% id, headers=dict(Accept='application/json'),\n                        url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n          time.sleep(10)\n    except Exception as err:\n      time.sleep(5)\n      return\n\ndef get_transport_node_profile_id (module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_profile_name):\n    try:\n      return get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                       \"/transport-node-profiles\", transport_node_profile_name)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (transport_node_profile_name, to_native(err)))\n\ndef get_compute_collection_id (module, manager_url, mgr_username, mgr_password, validate_certs, manager_name, cluster_name):\n    try:\n      (rc, resp) = request(manager_url+ '/fabric/compute-collections', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      compute_manager_id = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                                        \"/fabric/compute-managers\", manager_name)\n    except Exception as err:\n      module.fail_json(msg='Error accessing compute collection id for manager %s, cluster %s. Error [%s]' % (manager_name, cluster_name, to_native(err)))\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == cluster_name and \\\n            result['origin_id'] == compute_manager_id:\n            return result['external_id']\n    module.fail_json(msg='No compute collection id exist with cluster name %s for compute manager %s' % (cluster_name, manager_name))\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_collection_params ):\n    compute_manager_name = transport_node_collection_params.pop('compute_manager_name', None)\n    compute_cluster_name = transport_node_collection_params.pop('cluster_name', None)\n    compute_collection_id = get_compute_collection_id (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                                        compute_manager_name, compute_cluster_name)\n    transport_node_collection_params['compute_collection_id'] = compute_collection_id\n\n    transport_node_profile_name = transport_node_collection_params.pop('transport_node_profile_name', None)\n    transport_node_profile_id = get_transport_node_profile_id (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                                        transport_node_profile_name)\n    transport_node_collection_params['transport_node_profile_id'] = transport_node_profile_id\n    return transport_node_collection_params\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_collection_with_ids):\n    existing_tnc = get_transport_node_collection_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_collection_with_ids['display_name'])\n    if existing_tnc is None:\n        return False\n    if existing_tnc['compute_collection_id'] == transport_node_collection_with_ids['compute_collection_id'] and \\\n            existing_tnc['transport_node_profile_id'] != \\\n            transport_node_collection_with_ids['transport_node_profile_id']:\n        return True\n    if existing_tnc.__contains__('description') and not transport_node_collection_with_ids.__contains__('description'):\n        return True\n    if not existing_tnc.__contains__('description') and transport_node_collection_with_ids.__contains__('description'):\n        return True\n    if existing_tnc.__contains__('description') and transport_node_collection_with_ids.__contains__('description') and \\\n            existing_tnc['description'] != transport_node_collection_with_ids['description']:\n        return True\n    if existing_tnc.__contains__('transport_node_profile_name') and \\\n            transport_node_collection_with_ids.__contains__('transport_node_profile_name') \\\n            and existing_tnc['transport_node_profile_name'] != \\\n            transport_node_collection_with_ids['transport_node_profile_name']:\n        return True\n    if existing_tnc.__contains__('tags') and not transport_node_collection_with_ids.__contains__('tags'):\n        return True\n    if not existing_tnc.__contains__('tags') and transport_node_collection_with_ids.__contains__('tags'):\n        return True\n    if existing_tnc.__contains__('tags') and transport_node_collection_with_ids.__contains__('tags') and \\\n            (not compareTags(existing_tnc, transport_node_collection_with_ids)):\n        return True\n    return False\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                    description=dict(required=True, type='str'),\n                    resource_type=dict(required=True, type='str'),\n                    transport_node_profile_name=dict(required=True, type='str'),\n                    compute_manager_name=dict(required=False, type='str'),\n                    cluster_name=dict(required=False, type='str'),\n                    state=dict(required=True, choices=['present', 'absent']),\n                    tags=dict(required=False, type='list'))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  transport_node_collections_params = get_transport_node_collections_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  transport_node_collections_dict = get_transport_node_collection_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  transport_node_collection_id, revision = None, None\n  if transport_node_collections_dict:\n    transport_node_collection_id = transport_node_collections_dict['id']\n    revision = transport_node_collections_dict['_revision']\n\n  if state == 'present':\n    body = update_params_with_id(module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_collections_params)\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, body)\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n    if not updated:\n      # add the transport_node_collections\n      request_data = json.dumps(transport_node_collections_params)\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(request_data), id='12345')\n      try:\n          if transport_node_collection_id:\n              module.exit_json(changed=False, id=transport_node_collection_id,\n              message=\"transport-node-collection with display_name %s already exist on cluster %s.\" % (module.params['display_name'], module.params['cluster_name']))\n          (rc, resp) = request(manager_url+ '/transport-node-collections', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n                module.fail_json(msg=\"Failed to add transport_node_collections. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"transport-node-collection created for cluster %s.\" % module.params['cluster_name'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(transport_node_collections_params)), id=transport_node_collection_id)\n      transport_node_collections_params['_revision'] = revision # update current revision\n      request_data = json.dumps(transport_node_collections_params)\n      id = transport_node_collection_id\n      try:\n          (rc, resp) = request(manager_url+ '/transport-node-collections/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update transport_node_collections with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"transport-node-collection with Compute collection fabric template id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = transport_node_collection_id\n    if id is None:\n        module.exit_json(changed=False, msg='No transport-node-collection exist with display_name %s' % display_name)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(transport_node_collections_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/transport-node-collections/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete transport-node-collection with name %s. Error[%s].\" % (display_name, to_native(err)))\n\n    wait_till_delete(id, module, manager_url, mgr_username, mgr_password, validate_certs)\n\n    module.exit_json(changed=True, id=id, message=\"transport-node-collection with name %s deleted.\" % display_name)\n\n\ndef compareTags(existing_tnc, new_tnc):\n    return ordered(existing_tnc['tags']) == ordered(new_tnc['tags'])\n\n\ndef ordered(obj):\n    if isinstance(obj, dict):\n        return sorted((k, ordered(v)) for k, v in obj.items())\n    if isinstance(obj, list):\n        return sorted(ordered(x) for x in obj)\n    else:\n        return obj\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_transport_node_collections_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_transport_node_collections_facts\nshort_description: List Transport Node collections\ndescription: Returns all Transport Node collections\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: List Transport Node collections\n  nsxt_fabric_compute_managers_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils.urls import open_url, fetch_url\nfrom ansible.module_utils._text import to_native\nfrom ansible.module_utils.six.moves.urllib.error import HTTPError\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/transport-node-collections', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing transport-node-collections. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_transport_node_profiles.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_transport_node_profiles\nshort_description: Create a Transport Node Profile\ndescription: \"Transport node profile captures the configuration needed to create\na transport node. A transport node profile can be attached to\ncompute collections for automatic TN creation of member hosts.\"\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n    description:\n        description: Description of the pre/post-upgrade check\n        required: false\n        type: str\n    display_name:\n        description: Display name\n        required: true\n        type: str\n    host_switch_spec:\n        description: 'The HostSwitchSpec is the base class for standard and preconfigured\n                      host switch specifications. Only standard host switches are supported\n                      in the transport node profile.'\n        host_switches:\n            description: Transport Node host switches\n            required: true\n            type: array of HostSwitch\n        required: false\n        resource_type:\n            description: Selects the type of the transport zone profile\n            required: true\n            type: str\n        type: dict\n    resource_type:\n        description: Selects the type of the transport zone profile\n        required: true\n        type: str\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'. \n                      'present' is used to create or update resource. \n                      'absent' is used to delete resource.\"\n        required: true\n'''\n\nEXAMPLES = '''\n- name: Create transport node profile\n  nsxt_transport_node_profiles:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    resource_type: \"TransportNodeProfile\"\n    display_name: \"NSX Configured TNP\"\n    description: \"NSX configured Test Transport Node Profile\"\n    host_switch_spec:\n      resource_type: \"StandardHostSwitchSpec\"\n      host_switches:\n      - host_switch_profiles:\n        - name: \"uplinkProfile1\"\n          type: \"UplinkHostSwitchProfile\"\n        host_switch_name: \"hostswitch1\"\n        host_switch_mode: \"STANDARD\"\n        pnics:\n        - device_name: \"vmnic1\"\n          uplink_name: \"uplink-1\"\n        ip_assignment_spec:\n          resource_type: \"StaticIpPoolSpec\"\n          ip_pool_name: \"IPPool-IPV4-1\"\n        transport_zone_endpoints:\n        - transport_zone_name: \"TZ1\"\n        vmk_install_migration:\n        - device_name: vmk0\n          destination_network_name: \"ls_vmk_Mgmt\"\n    state: \"present\"\n\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\n\nFAILED_STATES = [\"failed\"]\nIN_PROGRESS_STATES = [\"pending\", \"in_progress\"]\nSUCCESS_STATES = [\"partial_success\", \"success\"]\nFABRIC_VIRTUAL_SWITCH_TYPE = [\"VDS\"]\n\ndef get_transport_node_profile_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_transport_node_profiles(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/transport-node-profiles', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing transport node profiles. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_host_switch_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name, exit_if_not_found=True):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['uuid']\n    if exit_if_not_found:\n        module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name, exit_if_not_found=True):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['id']\n    if exit_if_not_found:\n        module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef get_tnp_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    transport_node_profiles = get_transport_node_profiles(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for transport_node_profile in transport_node_profiles['results']:\n        if transport_node_profile.__contains__('display_name') and transport_node_profile['display_name'] == display_name:\n            return transport_node_profile\n    return None\n\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_profile_params ):\n    for host_switch in transport_node_profile_params['host_switch_spec']['host_switches']:\n        if host_switch.__contains__('host_switch_type') and host_switch['host_switch_type'] in FABRIC_VIRTUAL_SWITCH_TYPE:\n            if host_switch.__contains__('host_switch_name'):\n                host_switch['host_switch_id'] = get_host_switch_id_from_display_name(module, manager_url, mgr_username, \n                                                                     mgr_password, validate_certs,\n                                                                     '/fabric/virtual-switches', host_switch['host_switch_name'])\n            else:\n                module.fail_json(msg='Failing as host_switch_name is not provided for host switch of type: %s' % host_switch['host_switch_type'])\n        host_switch_profiles = host_switch.pop('host_switch_profiles', None)\n        host_switch_profile_ids = []\n        for host_switch_profile in host_switch_profiles:\n            profile_obj = {}\n            profile_obj['value'] = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                                    \"/host-switch-profiles?include_system_owned=true\", host_switch_profile['name'])\n            profile_obj['key'] = host_switch_profile['type']\n            host_switch_profile_ids.append(profile_obj)\n        host_switch['host_switch_profile_ids'] = host_switch_profile_ids\n        ip_pool_id = None\n        if host_switch.__contains__('ip_assignment_spec'):\n            if host_switch['ip_assignment_spec'].__contains__('ip_pool_name'):\n                ip_pool_name = host_switch['ip_assignment_spec'].pop('ip_pool_name', None)\n                host_switch['ip_assignment_spec']['ip_pool_id'] = get_id_from_display_name (module, manager_url,\n                                                                                        mgr_username, mgr_password, validate_certs,\n                                                                                        \"/pools/ip-pools\", ip_pool_name)\n        if host_switch.__contains__('transport_zone_endpoints'):\n            for transport_zone_endpoint in host_switch['transport_zone_endpoints']:\n                transport_zone_name = transport_zone_endpoint.pop('transport_zone_name', None)\n                transport_zone_endpoint['transport_zone_id'] = get_id_from_display_name (module, manager_url,\n                                                                                    mgr_username, mgr_password, validate_certs,\n                                                                                    \"/transport-zones\", transport_zone_name)\n        if host_switch.__contains__('vmk_install_migration'):\n            for vmk_install_migration in host_switch['vmk_install_migration']:\n                if vmk_install_migration.__contains__('destination_network_name'):\n                    destination_network_name = vmk_install_migration.pop('destination_network_name', None)\n                    vmk_install_migration['destination_network'] = get_id_from_display_name (module, manager_url,\n                                                                                        mgr_username, mgr_password, validate_certs,\n                                                                                        \"/logical-switches\", destination_network_name)\n    if transport_node_profile_params.__contains__('transport_zone_endpoints'):\n        for transport_zone_endpoint in transport_node_profile_params['transport_zone_endpoints']:\n            transport_zone_name = transport_zone_endpoint.pop('transport_zone_name', None)\n            transport_zone_endpoint['transport_zone_id'] = get_id_from_display_name (module, manager_url,\n                                                                                    mgr_username, mgr_password, validate_certs,\n                                                                                    \"/transport-zones\", transport_zone_name)\n    transport_node_profile_params['display_name'] = transport_node_profile_params.pop('display_name', None)\n    return transport_node_profile_params\n\n\ndef id_exist_in_list_dict_obj(key, list_obj1, list_obj2):\n    all_id_presents = False\n    if len(list_obj1) != len(list_obj2):\n        return all_id_presents\n    for dict_obj1 in list_obj1:\n        if dict_obj1.__contains__(key):\n            for dict_obj2 in list_obj2:\n                if dict_obj2.__contains__(key) and dict_obj1[key] == dict_obj2[key]:\n                    all_id_presents = True\n                    continue\n            if not all_id_presents:\n                return False\n    return True\n\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_profile_with_ids):\n    existing_transport_node_profile = get_tnp_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_profile_with_ids['display_name'])\n    if existing_transport_node_profile is None:\n        return False\n    if existing_transport_node_profile.__contains__('transport_zone_endpoints') and transport_node_profile_with_ids.__contains__('transport_zone_endpoints'):\n        return not id_exist_in_list_dict_obj('transport_zone_id', existing_transport_node_profile['transport_zone_endpoints'], transport_node_profile_with_ids['transport_zone_endpoints'])\n    if existing_transport_node_profile.__contains__('host_switch_spec') and existing_transport_node_profile['host_switch_spec'].__contains__('host_switches') and \\\n        transport_node_profile_with_ids.__contains__('host_switch_spec') and transport_node_profile_with_ids['host_switch_spec'].__contains__('host_switches') and \\\n        existing_transport_node_profile['host_switch_spec']['host_switches'] != transport_node_profile_with_ids['host_switch_spec']['host_switches']:\n        return True\n    if existing_transport_node_profile.__contains__('tags') and not transport_node_profile_with_ids.__contains__('tags'):\n        return True\n    if not existing_transport_node_profile.__contains__('tags') and transport_node_profile_with_ids.__contains__('tags'):\n        return True\n    if existing_transport_node_profile.__contains__('tags') and transport_node_profile_with_ids.__contains__('tags') and (not compareTags(existing_transport_node_profile, transport_node_profile_with_ids)):\n        return True\n    return False\n\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                description=dict(required=False, type='str'),\n                host_switch_spec=dict(required=False, type='dict',\n                host_switches=dict(required=True, type='list'),\n                resource_type=dict(required=True, type='str')),\n                resource_type=dict(required=True, type='str'),\n                transport_zone_endpoints=dict(required=False, type='list'),\n                state=dict(required=True, choices=['present', 'absent']),\n                tags=dict(required=False, type='list'))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  transport_node_profile_params = get_transport_node_profile_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  transport_node_profile_dict = get_tnp_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  transport_node_profile_id, revision = None, None\n  if transport_node_profile_dict:\n    transport_node_profile_id = transport_node_profile_dict['id']\n    revision = transport_node_profile_dict['_revision']\n\n  if state == 'present':\n    body = update_params_with_id(module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_profile_params)\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, body)\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n\n    if not updated:\n      # add the node\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(logical_switch_params)), id='12345')\n      request_data = json.dumps(body)\n      try:\n          if not transport_node_profile_id:\n              transport_node_profile_id = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, '/transport-node-profiles', display_name, exit_if_not_found=False)\n          if transport_node_profile_id:\n              module.exit_json(changed=False, id=transport_node_profile_id, message=\"Transport node profile with display_name %s already exist.\"% module.params['display_name'])\n\n          (rc, resp) = request(manager_url+ '/transport-node-profiles', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n           module.fail_json(msg=\"Failed to add transport node profile. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"transport node profile with display name %s created.\" % module.params['display_name'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(body)), id=transport_node_profile_id)\n\n      body['_revision'] = revision # update current revision\n      request_data = json.dumps(body)\n      id = transport_node_profile_id\n      try:\n          (rc, resp) = request(manager_url+ '/transport-node-profiles/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update transport node profile with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"transport node profile with node id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = transport_node_profile_id\n    if id is None:\n        module.exit_json(changed=False, msg='No transport node profile exist with display name %s' % display_name)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(transport_node_profile_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/transport-node-profiles/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete transport node profile with id %s. Error[%s].\" % (id, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=id, message=\"transport node profile with node id %s deleted.\" % id)\n\n\ndef compareTags(existing_tnp, new_tnp):\n    return ordered(existing_tnp['tags']) == ordered(new_tnp['tags'])\n\n\ndef ordered(obj):\n    if isinstance(obj, dict):\n        return sorted((k, ordered(v)) for k, v in obj.items())\n    if isinstance(obj, list):\n        return sorted(ordered(x) for x in obj)\n    else:\n        return obj\n\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_transport_node_profiles_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_transport_node_profiles_facts\nshort_description: List Transport Nodes Profiles\ndescription: Returns information about all transport node profiles.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n\n'''\n\nEXAMPLES = '''\n- name: List Transport Node Profiles\n  nsxt_transport_node_profiles_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/transport-node-profiles', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing transport node profiles. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_transport_nodes.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE\n# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_transport_nodes\nshort_description: Create a Transport Node\ndescription: \"Transport nodes are hypervisor hosts and NSX Edges that will participate\n              in an NSX-T overlay. For a hypervisor host, this means that it hosts\n              VMs that will communicate over NSX-T logical switches. For NSX Edges,\n              this means that it will have logical router uplinks and downlinks.\n\n              This API creates transport node for a host node (hypervisor) or edge node\n              (router) in the transport network.\n\n              When you run this command for a host, NSX Manager attempts to install the\n              NSX kernel modules, which are packaged as VIB, RPM, or DEB files. For the\n              installation to succeed, you must provide the host login credentials and the\n              host thumbprint.\n\n              To get the ESXi host thumbprint, SSH to the host and run the\n              <b>openssl x509 -in /etc/vmware/ssl/rui.crt -fingerprint -sha256 -noout</b>\n              command.\n\n              To generate host key thumbprint using SHA-256 algorithm please follow the\n              steps below.\n\n              Log into the host, making sure that the connection is not vulnerable to a\n              man in the middle attack. Check whether a public key already exists.\n              Host public key is generally located at '/etc/ssh/ssh_host_rsa_key.pub'.\n              If the key is not present then generate a new key by running the following\n              command and follow the instructions.\n\n              <b>ssh-keygen -t rsa</b>\n\n              Now generate a SHA256 hash of the key using the following command. Please\n              make sure to pass the appropriate file name if the public key is stored with\n              a different file name other than the default 'id_rsa.pub'.\n\n              <b>awk '{print $2}' id_rsa.pub | base64 -d | sha256sum -b | sed 's/ .*$//' | xxd -r -p | base64</b>\n              This api is deprecated as part of FN+TN unification. Please use Transport Node API\n              to install NSX components on a node.\n\n              Additional documentation on creating a transport node can be found\n              in the NSX-T Installation Guide.\n\n              In order for the transport node to forward packets,\n              the host_switch_spec property must be specified.\n\n              Host switches (called bridges in OVS on KVM hypervisors) are the\n              individual switches within the host virtual switch. Virtual machines\n              are connected to the host switches.\n\n              When creating a transport node, you need to specify if the host switches\n              are already manually preconfigured on the node, or if NSX should create\n              and manage the host switches. You specify this choice by the type\n              of host switches you pass in the host_switch_spec property of the\n              TransportNode request payload.\n\n              For a KVM host, you can preconfigure the host switch, or you can have\n              NSX Manager perform the configuration. For an ESXi host or NSX Edge\n              node, NSX Manager always configures the host switch.\n\n              To preconfigure the host switches on a KVM host, pass an array\n              of PreconfiguredHostSwitchSpec objects that describes those host\n              switches. In the current NSX-T release, only one prefonfigured host\n              switch can be specified.  See the PreconfiguredHostSwitchSpec schema\n              definition for documentation on the properties that must be provided.\n              Preconfigured host switches are only supported on KVM hosts, not on\n              ESXi hosts or NSX Edge nodes.\n\n              To allow NSX to manage the host switch configuration on KVM hosts,\n              ESXi hosts, or NSX Edge nodes, pass an array of StandardHostSwitchSpec\n              objects in the host_switch_spec property, and NSX will automatically\n              create host switches with the properties you provide. In the current\n              NSX-T release, up to 5 host switches can be automatically managed.\n              See the StandardHostSwitchSpec schema definition for documentation on\n              the properties that must be provided.\n\n              Note: previous versions of NSX-T used a property named host_switches\n              to specify the host switch configuration on the transport node. That\n              property is deprecated, but still functions. You should configure new\n              host switches using the host_switch_spec property.\n\n              The request should either provide node_deployement_info or node_id.\n\n              If the host node (hypervisor) or edge node (router) is already added in\n              system then it can be converted to transport node by providing node_id in\n              request.\n\n              If host node (hypervisor) or edge node (router) is not already present in\n              system then information should be provided under node_deployment_info.\"\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n    display_name:\n        description: Display name\n        required: true\n        type: str\n    description:\n        description: Description of this resource\n        required: False\n        type: str\n    resource_type:\n        description: Must be set to the value TransportNode\n        required: False\n        type: str\n    host_switch_spec:\n        description: 'This property is used to either create standard host switches\n                      or to inform NSX about preconfigured host switches that already\n                      exist on the transport node.\n                      Pass an array of either StandardHostSwitchSpec objects or\n                      PreconfiguredHostSwitchSpec objects. It is an error to pass\n                      an array containing different types of HostSwitchSpec objects.'\n        host_switches:\n            description: This property is deprecated in favor of 'host_switch_spec'. Property\n                          'host_switches' can only be used for NSX managed transport nodes. \n                          'host_switch_spec' can be used for both NSX managed or manually \n                          preconfigured host switches.\n            required: true\n            type: array of PreconfiguredHostSwitch\n        required: false\n        resource_type:\n            description: Selects the type of the transport zone profile\n            required: true\n            type: str\n        type: dict\n    maintenance_mode:\n        description: The property is read-only, used for querying result. User could update\n                      transport node maintenance mode by UpdateTransportNodeMaintenanceMode call.\n        required: false\n        type: str\n    node_deployment_info:\n        display_name:\n            description: Identifier to use when displaying entity in logs or GUI\n                         This field is deprecated.\n                         TransportNode field 'display_name' must be used instead. \n                         For HostNode, this field defaults to ID if not set.\n                         For EdgeNode and PublicCloudGatewayNode, this field is ignored if specified in request payload.\n            required: false\n            type: string\n        allocation_list:\n            description: List of logical router ids to which this edge node is allocated.\n            required: false\n            type: list\n        deployment_config:\n            description: 'When this configuration is specified, edge fabric node of deployment_type\n                          VIRTUAL_MACHINE will be deployed and registered with MP.'\n            form_factor:\n                description: Supported edge form factor.\n                required: false\n                type: str\n            node_user_settings:\n                audit_password:\n                    description: \"Password for the node audit user. For deployment, this property\n                                  is required. After deployment, this property is ignored, and\n                                  the node cli must be used to change the password. The password \n                                  specified must be at least 12 characters in length and must \n                                  contain at least one lowercase, one uppercase, one numeric \n                                  character and one special character (except quotes).\"\n                    required: false\n                    type: str\n                audit_username:\n                    description: \"The default username is 'audit'. To configure username, you\n                                  must provide this property together with <b>audit_password</b>.\"\n                    required: false\n                    type: str\n                cli_password:\n                    description: \"Password for the node cli user. For deployment, this property\n                                  is required. After deployment, this property is ignored, and \n                                  the node cli must be used to change the password. The password \n                                  specified must be at least 12 characters in length and must \n                                  contain at least one lowercase, one uppercase, one numeric \n                                  character and one special character (except quotes).\"\n                    required: false\n                    type: str\n                cli_username:\n                    description: \"To configure username, you must provide this property together \n                                  with <b>cli_password</b>.\"\n                    required: false\n                    type: str\n                description: \"Username and password settings for the node. Note - these settings\n                             will be honored only during node deployment. Post deployment, CLI \n                             must be used for changing the user settings, changes to these \n                             parameters will not have any effect.\"\n                required: true\n                root_password:\n                    description: \"Password for the node root user. For deployment, this property\n                                 is required. After deployment, this property is ignored, and the\n                                 node cli must be used to change the password. The password \n                                 specified must be at least 12 characters in length and must \n                                 contain at least one lowercase, one uppercase, one numeric \n                                 character and one special character (except quotes).\"\n                    required: false\n                    type: str\n                type: dict\n            required: false\n            type: dict\n            vm_deployment_config:\n                ipv4_assignment_enabled:\n                    description: 'Its a boolean flag, if assigned as false then Edge TN would be created using Static \n                    Ipv6 only. This field is deprecated.'\n                    required: false\n                    type: boolean\n                ipv6_assignment_type:\n                    description: 'IPv6 assignment type e.g STATIC, DHCPV6, SLAAC. if enum value is STATIC then\n                    management_port_subnets is mandatory. In this iteration DHCPV6 and SLAAC are\n                    not supported.'\n                    required: false\n                    type: str\n                compute:\n                    description: 'The cluster node VM will be deployed on the specified cluster\n                                  or resourcepool for specified VC server. If vc_username and \n                                  vc_password are present then this field takes name else id.'\n                    required: true\n                    type: str\n                data_networks:\n                    description: \"List of distributed portgroup or VLAN logical identifiers or names to\n                       which the datapath serving vnics of edge node vm will be connected. If vc_username \n                      and vc_password are present then this field takes names else id.\"\n                    required: true\n                    type: list\n                ignore_ssl_connection:\n                    description: 'This is a boolean value which will work as a flag to control whether SSL\n                        should be used while connecting to VC or not. \n                        If this is True, SSL will not be used to connect to VC.\n                        If the value is False, SSL will be used to connect to the VC. \n                        If this parameter is not specified, then it will be True.'\n                    required: false\n                    type: boolean\n                default_gateway_addresses:\n                    description: 'The default gateway for the VM to be deployed must be specified\n                                  if all the other VMs it communicates with are not in the same subnet.\n                                  Do not specify this field and management_port_subnets to use DHCP.\n                        \n                                  Note: only single IPv4 default gateway address is supported and it\n                                  must belong to management network.\n                        \n                                  IMPORTANT: VMs deployed using DHCP are currently not supported,\n                                  so this parameter should be specified.'\n                    required: false\n                    type: list\n                description: VM Deployment Configuration\n                host:\n                    description: \"Name of the host where edge VM is to be deployed\n                                  if vc_username and vc_password are present then\n                                  this field takes host name else host id.\"\n                    required: false\n                    type: str\n                management_network:\n                    description: 'Distributed portgroup identifier to which the management vnic\n                                  of cluster node VM will be connected. If vc_username and vc_password \n                                  are present then this field takes name else id.'\n                    required: true\n                    type: str\n                management_port_subnets:\n                    description: 'IP Address and subnet configuration for the management port.\n                                  Do not specify this field and default_gateway_addresses to\n                                  use DHCP.\n                        \n                                  Note: only one IPv4 address is supported for the management \n                                  port.\n                        \n                                  IMPORTANT: VMs deployed using DHCP are currently not supported,\n                                  so this parameter should be specified.'\n                    required: false\n                    type: array of IPSubnet\n                placement_type:\n                    description: \"Specifies the config for the platform through which to deploy\n                       the VM\"\n                    required: true\n                    type: str\n                required: true\n                storage:\n                    description: Moref or name of the datastore in VC. If it is to be taken from 'Agent\n                                 VM Settings', then it should be empty If vc_username and vc_password are present then\n                                  this field takes name else id.\n                    required: true\n                    type: str\n                type: dict\n                vc_name:\n                    description: 'The VC-specific names will be resolved on this VC, so all\n                                  other identifiers specified in the config must belong to this vCenter \n                                  server.'\n                    required: true\n                    type: str\n                vc_username:\n                    description: 'Username of VC'\n                    required: false\n                    type: str\n                vc_password:\n                    description: 'VC Password'\n                    required: false\n                    type: str\n                reservation_info:\n                    description: 'Resource reservation for memory and CPU resources'\n                    required: false\n                    type: dict\n                    cpu_reservation:\n                        description: 'Guaranteed minimum allocation of CPU resources'\n                        required: false\n                        type: dict\n                        reservation_in_mhz:\n                            description: 'GCPU resevation in mhz'\n                            required: false\n                            type: int\n                        reservation_in_shares:\n                            description: 'CPU reservation in shares'\n                            required: false\n                            type: str\n                    memory_reservation:\n                        description: 'Guaranteed minimum allocation of memory resources'\n                        required: false\n                        type: dict\n                        reservation_percentage:\n                            description: 'Memory reservation percentage'\n                            required: false\n                            type: int\n                resource_allocation:\n                    description: 'Resource reservation settings'\n                    required: false\n                    type: dict\n                    cpu_count:\n                        description: 'CPU count'\n                        required: false\n                        type: int\n                    memory_allocation_in_mb:\n                        description: 'Memory allocation in MB'\n                        required: false\n                        type: int\n        node_settings:\n            description: \"Current configuration on edge node\n                          Reports the current configuration of the SSH, DHS, NTP and host name\n                          on this edge node. The deployment_config property is used during\n                          deployment and this counterpart property shows current values.\"\n            required: false\n            type: dict\n            allow_ssh_root_login:\n                description: \"Allowing root SSH logins is not recommended for security reasons.\n                              Edit of this property is not supported when updating transport node.\n                              Use the CLI to change this property.\"\n                required: false\n                type: boolean\n            dns_servers:\n                description: \"List of DNS servers.\"\n                required: false\n                type: list\n            enable_ssh:\n                description: \"Enabling SSH service is not recommended for security reasons.\"\n                required: false\n                type: boolean\n            hostname:\n                description: \"Enabling SSH service is not recommended for security reasons.\"\n                required: true\n                type: string\n            advanced_configuration:\n                description: \"Array of additional specific properties for advanced or cloud-\n                              specific deployments in key-value format.\"\n                required: false\n                type: list\n            ntp_servers:\n                description: \"List of NTP servers.\"\n                required: false\n                type: list\n            search_domains:\n                description: \"List of domain names that are used to complete unqualified host names.\"\n                required: false\n                type: list\n            syslog_servers:\n                description: \"List of Syslog server configuration.\"\n                required: false\n                type: list\n        deployment_type:\n            description: Specifies whether the service VM should be deployed on each host such\n                          that it provides partner service locally on the host, or whether the \n                          service VMs can be deployed as a cluster. If deployment_type is \n                          CLUSTERED, then the clustered_deployment_count should be provided.\n            required: false\n            type: str\n        description: None\n        discovered_ip_addresses:\n            description: Discovered IP Addresses of the fabric node, version 4 or 6\n            required: false\n            type: list\n        discovered_node_id:\n            description: Id of discovered node which was converted to create this node\n            required: false\n            type: str\n        external_id:\n            description: Current external id of this virtual machine in the system.\n            required: false\n            type: str\n        fqdn:\n            description: Domain name the entity binds to\n            required: false\n            type: str\n        host_credential:\n            description: Login credentials for the host\n            password:\n                description: Password for the user (optionally specified on PUT, unspecified\n                  on GET)\n                required: false\n                type: str\n            required: false\n            thumbprint:\n                description: Hexadecimal SHA256 hash of the vIDM server's X.509 certificate\n                required: false\n                type: str\n            type: dict\n            username:\n                description: Username value of the log\n                required: false\n                type: str\n        ip_addresses:\n            description: Interface IP addresses\n            required: false\n            type: array of IPv4Address\n        managed_by_server:\n            description: The id of the vCenter server managing the ESXi type HostNode\n            required: false\n            type: str\n        os_type:\n            description: OS type of the discovered node\n            required: true\n            type: str\n        os_version:\n            description: OS version of the discovered node\n            required: false\n            type: str\n        required: false\n        resource_type:\n            description: Selects the type of the transport zone profile\n            required: true\n            type: str\n        type: dict\n    remote_tunnel_endpoint:\n        description: Configuration for a remote tunnel endpoin\n        required: False \n        type: 'dict'\n        host_switch_name:\n            description: The host switch name to be used for the remote tunnel endpoint\n            required: True\n            type: 'str'\n        named_teaming_policy:\n            description: The named teaming policy to be used by the remote tunnel endpoint\n            required: False\n            type: 'str'\n        rtep_vlan:\n            description: VLAN id for remote tunnel endpoint\n            required: True\n            type: 'dict'\n            VlanID:\n                description: Virtual Local Area Network Identifier\n                required: False\n                type: 'int'\n        ip_assignment_spec:\n            description: Specification for IPs to be used with host switch remote tunnel endpoints\n            required: True\n            type: 'dict'\n            resource_type:\n                description: Resource type\n                required: True\n                type: 'str'\n            ip_pool_id:\n                description: IP pool id\n                required: False\n                type: 'str'\n            ip_list:\n                description: List of IPs for transport node host switch virtual tunnel endpoints\n                required: False\n                type: 'list'\n            ip_mac_list:\n                description: List of IPs and MACs for transport node host switch virtual tunnel endpoints \n                required: False\n                type: 'list'\n            default_gateway:\n                description: Default gateway\n                required: False\n                type: 'dict'\n                IPAddress:\n                    description: IPv4 or IPv6 address\n                    required: False\n                    type: 'str'\n            subnet_mask:\n                description: Subnet mask\n                required: False\n                type: 'dict'\n                IPAddress:\n                    description: IPv4 IPv6 address\n                    required: False\n                    type: 'str'\n    tags: \n        description: Opaque identifiers meaningful to the API user\n        required: False\n        type: array of Tag\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'. \n                      'present' is used to create or update resource. \n                      'absent' is used to delete resource.\"\n        required: true\n    \n'''\n\nEXAMPLES = '''\n- name: Create transport node\n  nsxt_transport_nodes:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    resource_type: \"TransportNode\"\n    display_name: \"NSX Configured TN\"\n    description: \"NSX configured Test Transport Node\"\n    host_switch_spec:\n      resource_type: \"StandardHostSwitchSpec\"\n      host_switches:\n      - host_switch_profiles:\n        - name: \"uplinkProfile1\"\n          type: \"UplinkHostSwitchProfile\"\n        host_switch_name: \"hostswitch1\"\n        pnics:\n        - device_name: \"vmnic1\"\n          uplink_name: \"uplink-1\"\n        ip_assignment_spec:\n          resource_type: \"StaticIpPoolSpec\"\n          ip_pool_name: \"IPPool-IPV4-1\"\n        transport_zone_endpoints:\n        - transport_zone_name: \"TZ1\"\n    node_deployment_info:\n      resource_type: \"HostNode\"\n      display_name: \"Host_1\"\n      ip_addresses: [\"10.149.55.21\"]\n      os_type: \"ESXI\"\n      os_version: \"6.5.0\"\n      host_credential:\n        username: \"root\"\n        password: \"ca$hc0w\"\n        thumbprint: \"e7fd7dd84267da10f991812ca62b2bedea3a4a62965396a04728da1e7f8e1cb9\"\n    state: \"present\"\n    \n    \n- name: Create edge transport nodes\n  vmware.ansible_for_nsxt.nsxt_transport_nodes:\n    hostname: \"{{mgr_0_ip_address}}\"\n    username: \"{{username}}\"\n    password: \"{{password}}\"\n    validate_certs: False\n    display_name: \"{{display_name}}\"\n    description: \"{{description}}\"\n    host_switch_spec:\n      resource_type: StandardHostSwitchSpec\n      host_switches:\n      - host_switch_profiles:\n        - name: \"{{uplink_profile_name}}\"\n          type: UplinkHostSwitchProfile\n        host_switch_name: \"{{host_switch_name}}\"\n        host_switch_mode: \"{{host_switch_mode}}\"\n        pnics:\n        - device_name: \"{{device_name}}\"\n          uplink_name: \"{{uplink_name}}\"\n        ip_assignment_spec:\n          resource_type: StaticIpPoolSpec\n          ip_pool_name: \"{{ip_pool_display_name}}\"\n        transport_zone_endpoints:\n        - transport_zone_name: \"{{transport_zone_display_name_1}}\"\n        - transport_zone_name: \"{{transport_zone_display_name_2}}\"\n    node_deployment_info:\n      resource_type: EdgeNode\n      display_name: \"{{node_display_name}}\"\n      deployment_type: VIRTUAL_MACHINE\n      fqdn: \"{{ip_address}}\"\n      ip_addresses:\n        - \"{{ip_address}}\"\n      node_settings:\n        allow_ssh_root_login: \"{{allow_ssh_root_login}}\"\n        enable_ssh: \"{{enable_ssh}}\"\n        dns_servers:\n        - \"{{dns_server}}\"\n        ntp_servers:\n        - \"{{ntp_server}}\"\n        hostname: \"{{node_display_name}}\"\n        search_domains:\n        - \"{{search_domains}}\"\n      tags:\n      - tag: \"{{edge_tag}}\"\n        scope: \"{{edge_scope}}\"\n      deployment_config:\n        form_factor: \"{{form_factor}}\"\n        node_user_settings:\n          cli_password: \"{{password}}\"\n          root_password: \"{{password}}\"\n        vm_deployment_config:\n          placement_type: VsphereDeploymentConfig\n          vc_name: \"{{prod_vc_display_name}}\"\n          vc_username: \"{{prod_vc_username}}\"\n          vc_password: \"{{prod_vc_password}}\"\n          host: \"{{prod_esx_ip}}\"\n          compute: \"{{prod_vc_cluster}}\"\n          storage: \"{{prod_vc_datastore}}\"\n          management_network: \"{{prod_vc_portgroup}}\"\n          data_networks:\n          - \"{{prod_vc_portgroup}}\"\n          - \"{{prod_vc_portgroup}}\"\n          - \"{{prod_vc_portgroup}}\"\n          management_port_subnets:\n          - ip_addresses:\n            - \"{{ip_address}}\"\n            prefix_length: \"{{prefix_length}}\"\n          default_gateway_addresses:\n          - \"{{gateway}}\"\n          reservation_info:\n            cpu_reservation:\n              reservation_in_mhz: \"{{reservation_in_mhz}}\"\n              reservation_in_shares: \"{{reservation_in_shares}}\"\n            memory_reservation:\n              reservation_percentage: \"{{reservation_percentage}}\"\n          resource_allocation:\n            cpu_count: \"{{cpu_count}}\"\n            memory_allocation_in_mb: \"{{memory_allocation_in_mb}}\"\n    tags:\n    - tag: \"{{edge_tn_tag}}\"\n      scope: \"{{edge_tn_scope}}\"\n    state: \"{{state}}\"\n\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request, get_vc_ip_from_display_name\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vcenter_utils import get_resource_id_from_name, get_data_network_id_from_name\nfrom ansible.module_utils._text import to_native\nimport socket\nimport hashlib\nimport ssl\nimport ipaddress\n\nFAILED_STATES = [\"failed\"]\nIN_PROGRESS_STATES = [\"pending\", \"in_progress\"]\nSUCCESS_STATES = [\"partial_success\", \"success\", \"NODE_READY\"]\nFABRIC_VIRTUAL_SWITCH_TYPE = [\"VDS\"]\n\ndef get_transport_node_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_transport_nodes(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/transport-nodes', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing transport nodes. Error [%s]' % (to_native(err)))\n    return resp\n\n\ndef get_discovered_nodes(module, manager_url, mgr_username, mgr_password, validate_certs):\n  try:\n    (rc, resp) = request(manager_url + '/fabric/discovered-nodes', headers=dict(Accept='application/json'),\n                         url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                         ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing discovered nodes. Error [%s]' % (to_native(err)))\n  return resp\n\ndef get_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint, display_name, exit_if_not_found=True):\n    try:\n      (rc, resp) = request(manager_url+ endpoint, headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n        if result.__contains__('display_name') and result['display_name'] == display_name:\n            return result['id']\n    if exit_if_not_found:\n        module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef get_tn_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    transport_nodes = get_transport_nodes(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for transport_node in transport_nodes['results']:\n        if transport_node.__contains__('display_name') and transport_node['display_name'] == display_name:\n            return transport_node\n    return None\n\ndef get_dn_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n  discovered_nodes = get_discovered_nodes(module, manager_url, mgr_username, mgr_password, validate_certs)\n  for discovered_node in discovered_nodes['results']:\n    if discovered_node.__contains__('display_name') and discovered_node['display_name'] == display_name:\n      return discovered_node\n  return None\n\ndef get_host_switch_id_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, endpoint,\n                                           display_name, exit_if_not_found=True):\n    try:\n      (rc, resp) = request(manager_url + endpoint, headers=dict(Accept='application/json'),\n                           url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                           ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing id for display name %s. Error [%s]' % (display_name, to_native(err)))\n\n    for result in resp['results']:\n      if result.__contains__('display_name') and result['display_name'] == display_name:\n        return result['uuid']\n    if exit_if_not_found:\n      module.fail_json(msg='No id exist with display name %s' % display_name)\n\ndef wait_till_create(node_id, module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      count = 0;\n      while True:\n          time.sleep(10)\n          count = count + 1\n          (rc, resp) = request(manager_url+ '/transport-nodes/%s/state'% node_id, headers=dict(Accept='application/json'),\n                        url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n          if any(resp['state'] in progress_status for progress_status in IN_PROGRESS_STATES) and \\\n          any(resp['node_deployment_state']['state'] in progress_status for progress_status in IN_PROGRESS_STATES):\n              if count == 360:\n                  #Wait for max 60 minutes for host to realize\n                  module.fail_json(msg= 'Error creating transport node: creation state %s, node_deployment_state %s, Failure message: %s'%(str(resp['state']), str(resp['node_deployment_state']['state']), str(resp['failure_message'])))\n          elif any(resp['state'] in progress_status for progress_status in SUCCESS_STATES) and\\\n          any(resp['node_deployment_state']['state'] in progress_status for progress_status in SUCCESS_STATES):\n              time.sleep(5)\n              return\n          elif any(resp['state'] in progress_status for progress_status in FAILED_STATES) or\\\n          any(resp['node_deployment_state']['state'] in progress_status for progress_status in FAILED_STATES):\n              module.fail_json(msg= 'Error creating transport node: creation state %s, node_deployment_state %s'%(str(resp['state']), str(resp['node_deployment_state']['state'])))\n          else:\n              if count == 360:\n                   module.fail_json(msg= 'Error creating transport node: creation state %s, node_deployment_state %s'%(str(resp['state']), str(resp['node_deployment_state']['state'])))\n    except Exception as err:\n      module.fail_json(msg='Error accessing transport node. Error [%s]' % (to_native(err)))\n\ndef wait_till_delete(vm_id, module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      while True:\n          (rc, resp) = request(manager_url+ '/transport-nodes/%s/state'% vm_id, headers=dict(Accept='application/json'),\n                        url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n          time.sleep(10)\n    except Exception as err:\n      time.sleep(5)\n      return\n\ndef cmp_dict(dict1, dict2): # dict1 contain dict2\n    #print dict2\n    for k2, v2 in dict2.items():\n        found = False\n        if k2 not in dict1:\n            continue\n        if type(v2) != list and dict1[k2] != dict2[k2]:\n            return False\n            \n        for obj2 in v2:\n            for obj1 in dict1[k2]:\n                if all(item in obj1.items() for item in obj2.items()):\n                           found = True\n        if not found:\n            return False\n    return True\n\ndef update_params_with_id (module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_params ):\n    if transport_node_params.__contains__('host_switch_spec'):\n        for host_switch in transport_node_params['host_switch_spec']['host_switches']:\n            if host_switch.__contains__('host_switch_type') and host_switch[\n              'host_switch_type'] in FABRIC_VIRTUAL_SWITCH_TYPE:\n                if host_switch.__contains__('host_switch_name'):\n                  host_switch['host_switch_id'] = get_host_switch_id_from_display_name(module, manager_url, mgr_username,\n                                                                                   mgr_password, validate_certs,\n                                                                                   '/fabric/virtual-switches',\n                                                                                   host_switch['host_switch_name'])\n                else:\n                  module.fail_json(\n                    msg='Failing as host_switch_name is not provided for host switch of type: %s' % host_switch[\n                      'host_switch_type'])\n            host_switch_profiles = host_switch.pop('host_switch_profiles', None)\n\n            host_switch_profile_ids = []\n            if host_switch_profiles is not None:\n                for host_switch_profile in host_switch_profiles:\n                    profile_obj = {}\n                    profile_obj['value'] = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                                        \"/host-switch-profiles?include_system_owned=true\", host_switch_profile['name'])\n                    profile_obj['key'] = host_switch_profile['type']\n                    host_switch_profile_ids.append(profile_obj)\n            host_switch['host_switch_profile_ids'] = host_switch_profile_ids\n            ip_pool_id = None\n            if host_switch.__contains__('ip_assignment_spec') and host_switch['ip_assignment_spec']['resource_type'] == 'StaticIpPoolSpec':\n                ip_pool_name = host_switch['ip_assignment_spec'].pop('ip_pool_name', None)\n                host_switch['ip_assignment_spec']['ip_pool_id'] = get_id_from_display_name (module, manager_url,\n                                                                                            mgr_username, mgr_password, validate_certs,\n                                                                                            \"/pools/ip-pools\", ip_pool_name)\n            if host_switch.__contains__('transport_zone_endpoints'):\n                for transport_zone_endpoint in host_switch['transport_zone_endpoints']:\n                    transport_zone_name = transport_zone_endpoint.pop('transport_zone_name', None)\n                    transport_zone_endpoint['transport_zone_id'] = get_id_from_display_name (module, manager_url,\n                                                                                             mgr_username, mgr_password, validate_certs,\n                                                                                             \"/transport-zones\", transport_zone_name)\n            if host_switch.__contains__('vmk_install_migration'):\n                for network in host_switch['vmk_install_migration']:\n                    if network.__contains__('destination_network'):\n                        network['destination_network'] = get_id_from_display_name (module, manager_url, mgr_username,\n                                                                                   mgr_password, validate_certs,\n                                                                                   \"/logical-switches\", network['destination_network'])\n\n    if transport_node_params.__contains__('transport_zone_endpoints'):\n        for transport_zone_endpoint in transport_node_params['transport_zone_endpoints']:\n            transport_zone_name = transport_zone_endpoint.pop('transport_zone_name', None)\n            transport_zone_endpoint['transport_zone_id'] = get_id_from_display_name (module, manager_url,\n                                                                                    mgr_username, mgr_password, validate_certs,\n                                                                                    \"/transport-zones\", transport_zone_name)\n    if transport_node_params.__contains__('node_deployment_info') and transport_node_params['node_deployment_info'].__contains__('resource_type') and transport_node_params['node_deployment_info']['resource_type'] == 'EdgeNode':\n        vc_name = transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('vc_name', None)\n        transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']['vc_id'] = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                    \"/fabric/compute-managers\", vc_name)\n\n    transport_node_params['display_name'] = transport_node_params.pop('display_name', None)\n    return transport_node_params\n\ndef id_exist_in_list_dict_obj(key, list_obj1, list_obj2):\n    all_id_presents = False\n    if len(list_obj1) != len(list_obj2):\n        return all_id_presents\n    for dict_obj1 in list_obj1:\n        if dict_obj1.__contains__(key):\n            for dict_obj2 in list_obj2:\n                if dict_obj2.__contains__(key) and dict_obj1[key] == dict_obj2[key]:\n                    all_id_presents = True\n                    continue\n            if not all_id_presents:\n                return False\n    return True\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_with_ids):\n    existing_transport_node = get_tn_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_with_ids['display_name'])\n    \n    if existing_transport_node is None:\n        return False\n    if not existing_transport_node.__contains__('description') and transport_node_with_ids.__contains__('description'):\n        return True\n    if existing_transport_node.__contains__('description') and transport_node_with_ids.__contains__('description') and existing_transport_node['description'] != transport_node_with_ids['description']:\n        return True\n    if existing_transport_node.__contains__('description') and not transport_node_with_ids.__contains__('description'):\n        return True\n    if existing_transport_node.__contains__('tags') and not transport_node_with_ids.__contains__('tags'):\n        return True\n    if not existing_transport_node.__contains__('tags') and transport_node_with_ids.__contains__('tags'):\n        return True\n    if existing_transport_node.__contains__('tags') and transport_node_with_ids.__contains__('tags') and (not compareTags(existing_transport_node, transport_node_with_ids)):\n        return True\n\n    if transport_node_with_ids.__contains__('host_switch_spec') and transport_node_with_ids['host_switch_spec'].__contains__('host_switches'):\n        existing_host_switches = existing_transport_node['host_switch_spec']['host_switches']\n        sorted_existing_host_switches = sorted(existing_host_switches, key = lambda i: i['host_switch_name'])\n        sorted_new_host_switches = sorted(transport_node_with_ids['host_switch_spec']['host_switches'], key = lambda i: i['host_switch_name'])\n        if len(sorted_existing_host_switches) != len(sorted_new_host_switches):\n           return True\n        for i in range(len(sorted_existing_host_switches)):\n           diff_obj = {k: sorted_existing_host_switches[i][k] for k in sorted_existing_host_switches[i] if k in sorted_new_host_switches[i] and sorted_existing_host_switches[i][k] != sorted_new_host_switches[i][k]}\n           if not cmp_dict(diff_obj, sorted_new_host_switches[i]):\n              return True\n    return False\n\ndef get_api_cert_thumbprint(ip_address, module):\n    ip = ipaddress.ip_address(ip_address)\n    if isinstance(ip, ipaddress.IPv4Address):\n        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    elif isinstance(ip, ipaddress.IPv6Address):\n        sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)\n    sock.settimeout(1)\n    wrappedSocket = ssl.wrap_socket(sock)\n    try:\n        wrappedSocket.connect((ip_address, 443))\n    except Exception as err:\n        module.fail_json(msg='Failed to get node ID from ESXi host with IP {}. Error: {}'.format(ip_address, err))\n    else:\n        der_cert_bin = wrappedSocket.getpeercert(True)\n        thumb_sha256 = hashlib.sha256(der_cert_bin).hexdigest()\n        return thumb_sha256\n    finally:\n        wrappedSocket.close()\n\n\ndef inject_vcenter_info(module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_params):\n  '''\n  params:\n  - transport_node_params: These are the transport node parameters passed from playbook file\n  result:\n  - takes the vecenter parameters accepted by playbook and converts it into the form accepted\n    by transport node api using pyvmomi functions.\n  '''\n  vm_deployment_config = transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']\n  if vm_deployment_config.__contains__('ignore_ssl_verification'):\n      ignore_ssl_verification = vm_deployment_config['ignore_ssl_verification']\n  else:\n      ignore_ssl_verification = True\n  if vm_deployment_config.__contains__('vc_username') and vm_deployment_config.__contains__('vc_password'):\n    vc_name = vm_deployment_config['vc_name']\n    vc_ip = get_vc_ip_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs,\n                                         \"/fabric/compute-managers\", vc_name)\n    \n        \n    vc_username = transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('vc_username', None)\n        \n    vc_password = transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('vc_password', None)\n\n    if vm_deployment_config.__contains__('host'):\n      host = vm_deployment_config.pop('host', None)\n      host_id = get_resource_id_from_name(module, vc_ip, vc_username, vc_password,\n                                    'host', host, ignore_ssl_verification)\n      transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']['host_id'] = str(host_id)\n\n    storage = vm_deployment_config.pop('storage')\n    storage_id = get_resource_id_from_name(module, vc_ip, vc_username, vc_password,\n                                           'storage', storage, ignore_ssl_verification)\n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']['storage_id'] = str(storage_id)\n\n    cluster = vm_deployment_config.pop('compute')\n    cluster_id = get_resource_id_from_name(module, vc_ip, vc_username, vc_password,\n                                           'cluster', cluster, ignore_ssl_verification)\n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']['compute_id'] = str(cluster_id)\n\n    management_network = vm_deployment_config.pop('management_network')\n    management_network_id = get_resource_id_from_name(module, vc_ip, vc_username, vc_password,\n                                               'network', management_network, ignore_ssl_verification)\n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']['management_network_id'] = str(management_network_id)\n\n    data_networks = vm_deployment_config.pop('data_networks')\n    data_network_ids = get_data_network_id_from_name(module, vc_ip, vc_username, vc_password,\n                                                data_networks, ignore_ssl_verification)\n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']['data_network_ids'] = data_network_ids\n        \n    if vm_deployment_config.__contains__('host'):\n      transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('host', None)\n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('cluster', None)\n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('storage', None)\n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('management_network', None)\n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('data_networks', None)\n  else:\n    if vm_deployment_config.__contains__('host'):\n      host_id = transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('host', None)\n      transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']['host_id'] = host_id\n        \n    cluster_id = transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('compute', None)\n    storage_id = transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('storage', None)\n    management_network_id = transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('management_network', None)\n    data_network_ids = transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config'].pop('data_networks', None)\n        \n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']['compute_id'] = cluster_id\n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']['storage_id'] = storage_id\n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']['management_network_id'] = management_network_id\n    transport_node_params['node_deployment_info']['deployment_config']['vm_deployment_config']['data_network_ids'] = data_network_ids\n    transport_node_params['node_deployment_info']['vm_deployment_config'].pop('ignore_ssl_verification', None)\n\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                       ignore_ssl_verification=dict(required=False, type='boolean'),\n                       description=dict(required=False, type='str'),\n                       host_switch_spec=dict(required=False, type='dict',\n                       host_switches=dict(required=True, type='list'),\n                       resource_type=dict(required=True, type='str')),\n                       node_deployment_info=dict(required=False, type='dict',\n                       discovered_node_id=dict(required=False, type='str'),\n                       deployment_config=dict(required=False, type='dict',\n                       node_user_settings=dict(required=True, type='dict',\n                       cli_username=dict(required=False, type='str'),\n                       audit_username=dict(required=False, type='str'),\n                       root_password=dict(required=False, type='str', no_log=True),\n                       cli_password=dict(required=False, type='str', no_log=True),\n                       audit_password=dict(required=False, type='str', no_log=True)),\n                       vm_deployment_config=dict(required=True, type='dict',\n                       data_networks=dict(required=True, type='list'),\n                       management_network=dict(required=True, type='str'),\n                       vc_username=dict(required=False, type='str'),\n                       vc_password=dict(required=False, type='str', no_log=True),\n                       placement_type=dict(required=True, type='str'),\n                       compute=dict(required=True, type='str'),\n                       vc_name=dict(required=True, type='str'),\n                       ipv4_assignment_enabled=dict(required=False, type='boolean'),\n                       ipv6_assignment_type=dict(required=False, type='str'),\n                       storage=dict(required=True, type='str'),\n                       default_gateway_addresses=dict(required=False, type='list'),\n                       management_port_subnets=dict(required=False, type='list'),\n                       host=dict(required=False, type='str'),\n                       reservation_info=dict(required=False, type='dict',\n                       cpu_reservation=dict(required=False, type='dict',\n                       reservation_in_mhz=dict(required=False, type='int'),\n                       reservation_in_shares=dict(required=False, type='str')),\n                       memory_reservation=dict(required=False, type='dict',\n                       reservation_percentage=dict(required=False, type='int'))),\n                       resource_allocation=dict(required=False, type='dict',\n                       cpu_count=dict(required=False, type='int'),\n                       memory_allocation_in_mb=dict(required=False, type='int'))),\n                       form_factor=dict(required=False, type='str')),\n                       discovered_ip_addresses=dict(required=False, type='list'),\n                       ip_addresses=dict(required=False, type='list'),\n                       node_settings=dict(required=False, type='dict',\n                       advanced_configuration=dict(required=False, type='str'),\n                       allow_ssh_root_login=dict(required=False, type='boolean'),\n                       dns_servers=dict(required=False, type='str'),\n                       enable_ssh=dict(required=False, type='boolean'),\n                       hostname=dict(required=True, type='str'),\n                       ntp_servers=dict(required=False, type='list'),\n                       search_domains=dict(required=False, type='list'),\n                       syslog_servers=dict(required=False, type='list')),\n                       fqdn=dict(required=False, type='str'),\n                       os_version=dict(required=False, type='str'),\n                       managed_by_server=dict(required=False, type='str'),\n                       host_credential=dict(required=False, type='dict',\n                       username=dict(required=False, type='str'),\n                       password=dict(required=False, type='str', no_log=True),\n                       thumbprint=dict(required=False, type='str')),\n                       allocation_list=dict(required=False, type='list'),\n                       os_type=dict(required=True, type='str'),\n                       external_id=dict(required=False, type='str'),\n                       resource_type=dict(required=True, type='str'),\n                       deployment_type=dict(required=False, type='str')),\n                       maintenance_mode=dict(required=False, type='str'),\n                       remote_tunnel_endpoint=dict(required=False, type='dict',\n                       host_switch_name=dict(required=True, type='str'),\n                       named_teaming_policy=dict(required=False, type='str'),\n                       rtep_vlan=dict(required=True, type='dict',\n                       VlanID=dict(required=False, type='int')),\n                       ip_assignment_spec=dict(required=True, type='dict',\n                       resource_type=dict(required=True, type='str'),\n                       ip_pool_id=dict(required=False, type='str'),\n                       ip_list=dict(required=False, type='list'),\n                       ip_mac_list=dict(required=False, type='list'),\n                       default_gateway=dict(required=False, type='dict',\n                       IPAddress=dict(required=False, type='str')),\n                       subnet_mask=dict(required=False, type='dict',\n                       IPAddress=dict(required=False, type='str')))),\n                       tags=dict(required=False, type='list'),\n                       state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  transport_node_params = get_transport_node_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  discovered_node_dict = get_dn_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs,\n                                                 display_name)\n  discovered_node_id, revision, node_deployment_revision = None, None, None\n  if discovered_node_dict:\n    discovered_node_id = discovered_node_dict['external_id']\n\n  transport_node_dict = get_tn_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  transport_node_id, revision, node_deployment_revision = None, None, None\n  if transport_node_dict:\n    transport_node_id = transport_node_dict['id']\n    revision = transport_node_dict['_revision']\n\n  if state == 'present':\n    if transport_node_params.__contains__('node_deployment_info') and transport_node_params['node_deployment_info']['resource_type'] == 'EdgeNode':\n      inject_vcenter_info(module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_params)\n\n    body = update_params_with_id(module, manager_url, mgr_username, mgr_password, validate_certs, transport_node_params)\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, body)\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n    if not updated:\n      # add the node\n      if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(logical_switch_params)), id='12345')\n\n      if body[\"node_deployment_info\"].__contains__('host_credential'):\n        if body[\"node_deployment_info\"][\"host_credential\"].__contains__(\"thumbprint\"):\n          thumbprint = body[\"node_deployment_info\"][\"host_credential\"][\"thumbprint\"]\n        else:\n          if not body[\"node_deployment_info\"].__contains__(\"ip_addresses\"):\n            module.fail_json(msg=\"ESXi ip adresses are not provided\")\n          esxi_ip_address = body[\"node_deployment_info\"][\"ip_addresses\"][0]\n          thumbprint = get_api_cert_thumbprint(esxi_ip_address, module)\n          body[\"node_deployment_info\"][\"host_credential\"][\"thumbprint\"] = thumbprint\n      request_data = json.dumps(body)\n      try:\n          if not transport_node_id:\n              transport_node_id = get_id_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, '/transport-nodes', display_name, exit_if_not_found=False)\n          if transport_node_id:\n              module.exit_json(changed=False, id=transport_node_id, message=\"Transport node with display_name %s already exist.\"% module.params['display_name'])\n          if discovered_node_id:\n            (rc, resp) = request(manager_url + '/fabric/discovered-nodes/%s?action=create_transport_node' %discovered_node_id, data=request_data, headers=headers, method='POST',\n                                 url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                                 ignore_errors=True)\n          else:\n            (rc, resp) = request(manager_url+ '/transport-nodes', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n           module.fail_json(msg=\"Failed to add transport node. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      wait_till_create(resp['node_id'], module, manager_url, mgr_username, mgr_password, validate_certs)\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"node_id\"], body= str(resp), message=\"Transport node with display name %s created.\" % module.params['display_name'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(body)), id=transport_node_id)\n\n      body['_revision'] = revision # update current revision\n      \n      #update node id with tn id - as result of FN TN unification\n      body['node_id'] = transport_node_id\n\n      request_data = json.dumps(body)\n      id = transport_node_id\n      try:\n          (rc, resp) = request(manager_url+ '/transport-nodes/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update transport node with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"node_id\"], body= str(resp), message=\"Transport node with node id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = transport_node_id\n    if id is None:\n        module.exit_json(changed=False, msg='No transport node exist with display name %s' % display_name)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(transport_node_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/transport-nodes/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete transport node with id %s. Error[%s].\" % (id, to_native(err)))\n\n    wait_till_delete(id, module, manager_url, mgr_username, mgr_password, validate_certs)\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=id, message=\"Transport node with node id %s deleted.\" % id)\n\n\ndef compareTags(existing_transport_node, new_transport_nodes):\n    return ordered(existing_transport_node['tags']) == ordered(new_transport_nodes['tags'])\n\n\ndef ordered(obj):\n    if isinstance(obj, dict):\n        return sorted((k, ordered(v)) for k, v in obj.items())\n    if isinstance(obj, list):\n        return sorted(ordered(x) for x in obj)\n    else:\n        return obj\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_transport_nodes_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_transport_nodes_facts\nshort_description: List Transport Nodes\ndescription: Returns information about all transport nodes along with underlying host or\n              edge details. A transport node is a host or edge that contains hostswitches.\n              A hostswitch can have virtual machines connected to them.\n\n              Because each transport node has hostswitches, transport nodes can also have\n              virtual tunnel endpoints, which means that they can be part of the overlay.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n\n'''\n\nEXAMPLES = '''\n- name: List Transport Nodes\n  nsxt_transport_nodes_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/transport-nodes', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing transport zone. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_transport_zones.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_transport_zones\nshort_description: Create a Transport Zone\ndescription: \"Creates a new transport zone. The required parameters are host_switch_name\nand transport_type (OVERLAY or VLAN). The optional parameters are\ndescription and display_name. This api is now deprecated. Please use new api - \nPUT /infra/sites/<site-id>/enforcement-points/<enforcementpoint- \nid>/transport-zones/<zone-id>\"\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n    description:\n        description: Description of this resource\n        required: false\n    display_name:\n        description: Identifier to use when displaying entity in logs or GUI\n        required: true\n        type: str\n    is_default:\n        description: Only one transport zone can be the default one for a given transport\n                     zone type. APIs that need transport zone can choose to use the default \n                     transport zone if a transport zone is not given by the user.\n        required: false\n        type: boolean\n    nested_nsx:\n        description: The flag only need to be set in nested NSX environment.\n        required: false\n        type: boolean\n    resource_type:\n        description: Should be set to the value PolicyTransportZone\n        required: false\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'. \n                      'present' is used to create or update resource. \n                      'absent' is used to delete resource.\"\n        required: true\n    tz_type:\n        description: Valid values are OVERLAY_BACKED , VLAN_BACKED\n        required: true\n        type: str\n    tags:\n        description: Opaque identifier meaningful to API user\n        required: false\n        type: Array of Tag\n    transport_zone_profile_ids:\n        description: Identifiers of the transport zone profiles associated with this \n                     TransportZone.\n        required: false\n        type: array of TransportZoneProfileTypeIdEntry\n    uplink_teaming_policy_names:\n        description: The names of switching uplink teaming policies that all transport nodes\n                     in this transport zone must support. An exception will be thrown if a \n                     transport node within the transport zone does not support a named teaming\n                     policy. The user will need to first ensure all trasnport nodes support the \n                     desired named teaming policy before assigning it to the transport zone. \n                     If the field is not specified, the host switch's default teaming policy will \n                     be used.\n        required: false\n        type: list\n\n    enforcementpoint_id:\n        description: The EnforcementPoint ID where the TZ is located.\n                     Required if transport_zone_id is specified.\n        default: default\n        type: str\n    site_id:\n        description: The site ID where the EnforcementPoint is located.\n                     Required if transport_zone_id is specified.\n        default: default\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: Create transport zone\n  nsxt_transport_zones:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    resource_type: \"PolicyTransportZone\"\n    display_name: \"TZ1\"\n    description: \"NSX configured Test Transport Zone\"\n    tz_type: \"VLAN_BACKED\"\n    state: \"present\"\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import TRANSPORT_ZONE_URL\nfrom ansible.module_utils._text import to_native\n\n\ndef get_transport_zone_params(args=None):\n  args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n  for key in args_to_remove:\n    args.pop(key, None)\n  for key, value in args.copy().items():\n    if value == None:\n      args.pop(key, None)\n  return args\n\n\ndef get_transport_zone_baseURL(transport_zone_params):\n  if transport_zone_params.__contains__('display_name'):\n    site_id = transport_zone_params.pop(\"site_id\", 'default')\n    enforcementpoint_id = transport_zone_params.pop(\"enforcementpoint_id\", 'default')\n    transport_zone_base_url = (TRANSPORT_ZONE_URL.format(site_id, enforcementpoint_id))\n    return transport_zone_base_url\n\n\ndef get_transport_zones(module, manager_url, mgr_username, mgr_password, validate_certs, transport_zone_base_url):\n  try:\n    (rc, resp) = request(manager_url + transport_zone_base_url, method='GET',\n                         headers=dict(Accept='application/json'),\n                         url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                         ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing transport zones. Error [%s]' % (to_native(err)))\n  return resp\n\n\ndef get_tz_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name,transport_zone_base_url):\n  transport_zones = get_transport_zones(module, manager_url, mgr_username, mgr_password, validate_certs, transport_zone_base_url)\n  for transport_zone in transport_zones['results']:\n    if transport_zone.__contains__('display_name') and transport_zone['display_name'] == display_name:\n      return transport_zone\n  return None\n\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, transport_zone_params, transport_zone_base_url):\n  existing_transport_zone = get_tz_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs,\n                                                     transport_zone_params['display_name'], transport_zone_base_url)\n  if existing_transport_zone is None:\n    return False\n  if existing_transport_zone.__contains__('is_default') and transport_zone_params.__contains__('is_default') and \\\n          existing_transport_zone['is_default'] != transport_zone_params['is_default']:\n    return True\n  if not existing_transport_zone.__contains__('description') and transport_zone_params.__contains__('description'):\n    return True\n  if existing_transport_zone.__contains__('description') and not transport_zone_params.__contains__('description'):\n    return True\n  if existing_transport_zone.__contains__('description') and transport_zone_params.__contains__('description') and \\\n          existing_transport_zone['description'] != transport_zone_params['description']:\n    return True\n  if not existing_transport_zone.__contains__('uplink_teaming_policy_names') and transport_zone_params.__contains__(\n          'uplink_teaming_policy_names'):\n    return True\n  if existing_transport_zone.__contains__('uplink_teaming_policy_names') and not transport_zone_params.__contains__(\n          'uplink_teaming_policy_names'):\n    return True\n  if existing_transport_zone.__contains__('uplink_teaming_policy_names') and transport_zone_params.__contains__(\n          'uplink_teaming_policy_names') and \\\n          existing_transport_zone['uplink_teaming_policy_names'] != transport_zone_params[\n    'uplink_teaming_policy_names']:\n    return True\n  return False\n\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                       tz_type=dict(required=True, choice=['VLAN_BACKED', 'OVERLAY_BACKED']),\n                       nested_nsx=dict(required=False, type='bool'),\n                       uplink_teaming_policy_names=dict(required=False, type='list'),\n                       transport_zone_profile_paths=dict(required=False, type='list'),\n                       is_default=dict(required=False, type='bool'),\n                       resource_type=dict(required=False, type='str'),\n                       description=dict(required=False, type='str'),\n                       tags=dict(required=False, type='list'),\n                       state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  transport_zone_params = get_transport_zone_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/policy/api/v1'.format(mgr_hostname)\n  transport_zone_base_url = get_transport_zone_baseURL(transport_zone_params)\n  zone_dict = get_tz_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name,\n                                       transport_zone_base_url)\n  zone_id, revision = None, None\n  if zone_dict:\n    zone_id = zone_dict['id']\n    revision = zone_dict['_revision']\n\n  if state == 'present':\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs,\n                               transport_zone_params, transport_zone_base_url)\n\n    if not updated:\n      # add the node\n      if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(transport_zone_params)), id='12345')\n      request_data = json.dumps(transport_zone_params)\n      try:\n        if zone_id:\n          module.exit_json(changed=False, id=zone_id,\n                           message=\"Transport zone with display_name %s already exist.\" % module.params[\n                             'display_name'])\n        (rc, resp) = request(manager_url + transport_zone_base_url + '/%s' % module.params['display_name'],\n                             data=request_data, headers=headers, method='PUT',\n                             url_username=mgr_username, url_password=mgr_password,\n                             validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n        module.fail_json(\n          msg=\"Failed to add transport zone. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body=str(resp),\n                       message=\"Transport zone with display name %s created. \" % (module.params['display_name']))\n    else:\n      if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(transport_zone_params)), id=zone_id)\n\n      transport_zone_params['_revision'] = revision  # update current revision\n      request_data = json.dumps(transport_zone_params)\n      id = zone_id\n      try:\n        (rc, resp) = request(manager_url + transport_zone_base_url + '/%s' % id, data=request_data,\n                             headers=headers, method='PATCH',\n                             url_username=mgr_username, url_password=mgr_password,\n                             validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n        module.fail_json(msg=\"Failed to update transport zone with id %s. Request body [%s]. Error[%s].\" % (\n          id, request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body=str(resp),\n                       message=\"Transport zone with zone id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = zone_id\n    if id is None:\n      module.exit_json(changed=False, msg='No transport zone exist with display name %s' % display_name)\n    if module.check_mode:\n      module.exit_json(changed=True, debug_out=str(json.dumps(transport_zone_params)), id=id)\n    try:\n      (rc, resp) = request(manager_url + transport_zone_base_url + \"/%s\" % id, method='DELETE',\n                           url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n      module.fail_json(msg=\"Failed to delete transport zone with id %s. Error[%s].\" % (id, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=id, message=\"Transport zone with zone id %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n  main()\n"
  },
  {
    "path": "plugins/modules/nsxt_transport_zones_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_transport_zones_facts\nshort_description: List Transport Zones\ndescription: Returns information about configured transport zones. NSX requires at\n              least one transport zone. NSX uses transport zones to provide connectivity\n              based on the topology of the underlying network, trust zones, or\n              organizational separations. For example, you might have hypervisors that\n              use one network for management traffic and a different network for VM\n              traffic. This architecture would require two transport zones. The\n              combination of transport zones plus transport connectors enables NSX to\n              form tunnels between hypervisors. Transport zones define which interfaces\n              on the hypervisors can communicate with which other interfaces on other\n              hypervisors to establish overlay tunnels or provide connectivity to a VLAN.\n              A logical switch can be in one (and only one) transport zone. This means\n              that all of a switch's interfaces must be in the same transport zone.\n              However, each hypervisor virtual switch (OVS or VDS) has multiple\n              interfaces (connectors), and each connector can be attached to a different\n              logical switch. For example, on a single hypervisor with two connectors,\n              connector A can be attached to logical switch 1 in transport zone A, while\n              connector B is attached to logical switch 2 in transport zone B. In this\n              way, a single hypervisor can participate in multiple transport zones. The\n              API for creating a transport zone requires that a single host switch be\n              specified for each transport zone, and multiple transport zones can share\n              the same host switch.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n\n'''\n\nEXAMPLES = '''\n- name: List Transport Zones\n  nsxt_transport_zones_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/transport-zones', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing transport zone. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_eula_accept.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_eula_accept\nshort_description: 'Accept end user license agreement'\ndescription: \"Accept end user license agreement \"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: Accepts end user license agreement.\n  nsxt_upgrade_eula_accept:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import get_upgrade_orchestrator_node\nfrom ansible.module_utils._text import to_native\n\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n\n  mgr_hostname = get_upgrade_orchestrator_node(module, mgr_hostname, mgr_username, \n                                            mgr_password, headers, validate_certs)\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n \n  # Accept the upgrade EULA\n\n  if module.check_mode:\n    module.exit_json(changed=False, debug_out='Upgrade EULA will be'\n                                     ' accepted.', id=mgr_hostname)\n  try:\n    (rc, resp) = request(manager_url+ '/upgrade/eula/accept', data='',\n                         headers=headers, method='POST', url_username=mgr_username,\n                         url_password=mgr_password, validate_certs=validate_certs,\n                         ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Failed to accept end user license'\n                          ' agreement. Error[%s].' % to_native(err))\n\n  time.sleep(5)\n  module.exit_json(changed=True, result=resp, message='End user license agreement'\n                                                      ' is accepted.')\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_eula_accept_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_eula_accept_facts\nshort_description: 'Gets EULA acceptance status and contents'\ndescription: \"Returns EULA acceptance status and the contents.\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    required_info:\n        choices:\n            - acceptance\n            - contents\n        description: \"required_info can be either 'acceptance' or 'contents'.\n                      'acceptance' returns the acceptance status of end user license agreement .\n                      'contents' Return the content of end user license agreement in the specified format. \n                       By default, it's pure string without line break. \"\n        required: true\n'''\n\nEXAMPLES = '''\n- name: Gets EULA acceptance status and contents\n  nsxt_upgrade_eula_accept_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      required_info: \"acceptance\"\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import get_id_from_display_name_results\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(required_info=dict(required=True, type='str', \n                       choices=['acceptance', 'contents']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  required_info = module.params['required_info']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  if required_info == 'acceptance':\n    try:\n      (rc, resp) = request(manager_url + '/upgrade/eula/acceptance',\n                           headers=dict(Accept='application/json'), url_username=mgr_username,\n                           url_password=mgr_password, validate_certs=validate_certs,\n                           ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing upgrade EULA acceptance '\n                                    'status. Error [%s]' % (to_native(err)))\n    module.exit_json(changed=False, **resp)\n  elif required_info == 'contents':\n    try:\n      (rc, resp) = request(manager_url + '/upgrade/eula/content',\n                           headers=dict(Accept='application/json'), url_username=mgr_username,\n                           url_password=mgr_password, validate_certs=validate_certs,\n                           ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing upgrade EULA contents '\n                                    'status. Error [%s]' % (to_native(err)))\n\n    module.exit_json(changed=False, **resp)\n  else:\n    module.fail_json(msg='Invalid value passed for required_info.')\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_groups.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_groups\nshort_description: 'Create a group of upgrade units.'\ndescription: 'Create a group of upgrade units.'\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    type:\n        description: 'Component type'\n        required: true\n        type: str\n    parallel:\n        description: 'Upgrade Method to specify whether the upgrade is \n                      to be performed serially or in parallel'\n        required: false\n        type: boolean\n    upgrade_unit_count:\n        description: 'Count of upgrade units in the group'\n        required: false\n        type: int\n    upgrade_units:\n        description: 'List of upgrade units in the group'\n        required: false\n        type: list\n    enabled:\n        description: 'Flag to indicate whether upgrade of this group is enabled or not'\n        required: false\n        type: boolean\n    extended_configuration:\n        description: 'Extended configuration for the group'\n        required: false\n        type: list\n    resource_type:\n        description: 'Resource type'\n        required: false\n        type: str\n    tags:\n        description: 'Opaque identifiers meaningful to the API user'\n        required: false\n        type: list\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n'''\n\nEXAMPLES = '''\n- name: Modifies default upgrade Group\n  nsxt_upgrade_groups:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      display_name: \"MyUpgradeGroup\"\n      type: 'MP'\n      parallel: True\n      enabled: True\n      state: Present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import clean_and_get_params, get_id_from_display_name_results, get_upgrade_orchestrator_node\nfrom ansible.module_utils._text import to_native\n\ndef update_group_parameters(module, manager_url, \n                            mgr_username, mgr_password, \n                            validate_certs,\n                            upgrade_group_parameters):\n  if upgrade_group_parameters.__contains__('upgrade_units'):\n    for upgrade_unit in upgrade_group_parameters['upgrade_units']:\n      host_name = upgrade_unit.pop('host_name', None)\n      upgrade_unit_id = get_id_from_display_name_results(module, manager_url, \n                                     '/upgrade/upgrade-units', mgr_username,\n                                     mgr_password, validate_certs, \n                                     ['display_name'], ['id'],\n                                     host_name)\n      upgrade_unit['id']= upgrade_unit_id\n  return upgrade_group_parameters\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(description=dict(type='str', required=False),\n                       display_name=dict(type='str', required=True),\n                       enabled=dict(type='bool', required=False, default=True),\n                       extended_configuration=dict(type='list', required=False),\n                       parallel=dict(type='bool', required=False, default=True),\n                       resource_type=dict(type='str', required=False),\n                       tags=dict(type='list', required=False),\n                       type=dict(type='str', required=True),\n                       upgrade_unit_count=dict(type='int', required=False),\n                       upgrade_units=dict(type='list', required=False),\n                    state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  upgrade_group_params = clean_and_get_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n\n  mgr_hostname = get_upgrade_orchestrator_node(module, mgr_hostname, mgr_username, \n                                            mgr_password, headers, validate_certs)\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n\n  upgrade_group_params = update_group_parameters(module, manager_url, mgr_username, \n                                                 mgr_password, validate_certs, \n                                                 upgrade_group_params)\n\n  upgrade_unit_group_id = get_id_from_display_name_results(module, manager_url, \n                                        '/upgrade/upgrade-unit-groups', mgr_username, \n                                        mgr_password, validate_certs, ['display_name'], \n                                        ['id'], upgrade_group_params['display_name'], \n                                        False)\n  if state == 'present':\n    # create a new upgrade group or modify the existing one \n    if module.check_mode:\n      module.exit_json(changed=False, debug_out='A new upgrade unit will be created with'\n                                                ' name: %s' % module.params['display_name'])\n    request_data = json.dumps(upgrade_group_params)\n    if upgrade_unit_group_id is None:\n      try:\n        (rc, resp) = request(manager_url + '/upgrade/upgrade-unit-groups', \n                            data=request_data, headers=headers, method='POST', \n                            url_username=mgr_username, url_password=mgr_password, \n                            validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n        module.fail_json(msg=\"Failed to add upgrade group. Error[%s].\" % to_native(err))\n\n      time.sleep(5)\n      module.exit_json(changed=True, message=\"Upgrade group is added successfully.\")\n    else:\n      try:\n        (rc, resp) = request(manager_url + '/upgrade/upgrade-unit-'\n                            'groups/%s' % upgrade_unit_group_id,\n                            data=request_data, headers=headers, method='PUT', \n                            url_username=mgr_username, url_password=mgr_password, \n                            validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n        module.fail_json(msg=\"Failed to modify upgrade group. Error[%s].\" % to_native(err))\n\n      time.sleep(5)\n      module.exit_json(changed=True, message='Upgrade group with group id '\n                       '%s is updated.' % upgrade_unit_group_id)\n  elif state == 'absent':\n    # remove an existing upgrade group\n    try:\n       (rc, resp) = request(manager_url+ '/upgrade/upgrade-unit-groups'\n                            '/%s' % upgrade_unit_group_id, \n                            data='', headers=headers, method='DELETE',\n                            url_username=mgr_username, url_password=mgr_password, \n                            validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Failed while deleting the upgrade'\n                           ' group. Error[%s].' % to_native(err))\n\n    time.sleep(5)\n    module.exit_json(changed=True, message='Upgrade group with group id '\n                     '%s is deleted.' % upgrade_unit_group_id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_groups_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_group_facts\nshort_description: 'Get the upgrade groups information'\ndescription: 'Get the upgrade groups information'\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: Get the upgrade groups information\n  nsxt_upgrade_group_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url + '/upgrade/upgrade-unit-groups/aggregate-info',\n                         headers=dict(Accept='application/json'), url_username=mgr_username, \n                         url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error while retrieving upgrade group '\n                         'information. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\n\nif __name__ == '__main__':\n  main()"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_history.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_history\nshort_description: 'Get upgrade history'\ndescription: \"Get upgrade history\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: Get upgrade history\n  nsxt_upgrade_history:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/upgrade/history', headers=dict(Accept='application/json'),\n                         url_username=mgr_username, url_password=mgr_password,\n                         validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error while retrieving bundle information. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n  main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_plan.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_plan\nshort_description: 'Upgrade plan settings for the component'\ndescription: 'Upgrade plan settings for the component'\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    component_type:\n        description: 'Component whose upgrade plan is to be changed'\n        choices:\n            - host\n            - edge\n            - mp\n        required: true\n        type: str\n    parallel:\n        description: 'Upgrade Method to specify whether the upgrade is \n                      to be performed serially or in parallel'\n        required: true\n        type: boolean\n    pause_after_each_group:\n        description: 'Flag to indicate whether to pause the upgrade after\n                      upgrade of each group is completed'\n        required: true\n        type: boolean\n    pause_on_error:\n        description: 'Flag to indicate whether to pause the upgrade plan \n                      execution when an error occurs'\n        required: true\n        type: boolean\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n'''\n\nEXAMPLES = '''\n- name: Modifies default upgrade plan\n  nsxt_upgrade_plan:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      component_type: 'host'\n      parallel: True\n      pause_after_each_group: True\n      pause_on_error: True\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import get_attribute_from_endpoint, clean_and_get_params, get_upgrade_orchestrator_node\nfrom ansible.module_utils._text import to_native\n\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(component_type=dict(type='str', required=True, choices=['host', 'edge', 'mp']),\n                       parallel=dict(type='bool', required=False),\n                       pause_after_each_group=dict(type='bool', required=False),\n                       pause_on_error=dict(type='bool', required=False),\n                    state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  upgrade_plan_params = clean_and_get_params(module.params.copy(), ['component_type'])\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  component_type = module.params['component_type']\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n\n  mgr_hostname = get_upgrade_orchestrator_node(module, mgr_hostname, mgr_username, \n                                            mgr_password, headers, validate_certs)\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  if state == 'present':\n    # update the default upgrade plan\n    if module.check_mode:\n      module.exit_json(changed=False, debug_out='Upgrade Plan will be modified.'\n        ' parallel: %s, pause_after_each_group: %s, pause_on_error: %s' % \n        (module.params['parallel'], module.params['pause_after_each_group'], \n        module.params['pause_on_error']), id=module.params['component_type'])\n    request_data = json.dumps(upgrade_plan_params)\n    try:\n      (rc, resp) = request(manager_url+ '/upgrade/plan/%s/settings' % component_type.upper(), \n                           data=request_data, headers=headers, method='PUT', \n                           url_username=mgr_username, url_password=mgr_password, \n                           validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg=\"Failed to update upgrade plan. Error[%s].\" % to_native(err))\n\n    time.sleep(5)\n    module.exit_json(changed=True, message=\"Upgrade plan is updated.\")\n\n  elif state == 'absent':\n    # reset to default upgrade plan\n    try:\n       (rc, resp) = request(manager_url+ '/upgrade/plan?action=reset&'\n                            'component_type=%s' % component_type.upper(), \n                            data='', headers=headers, method='POST',\n                            url_username=mgr_username, url_password=mgr_password, \n                            validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg=\"Failed while reseting the upgrade plan. Error[%s].\" % to_native(err))\n\n    time.sleep(5)\n    module.exit_json(changed=True, message=\"Upgrade plan is reset.\")\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_plan_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_plan_facts\nshort_description: 'Get the upgrade plan settings for the component.'\ndescription: \"Get the upgrade plan settings for the component.\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    component_type:\n        description: 'Component whose upgrade plan is to be changed'\n        choices:\n            - host\n            - edge\n            - mp\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: Get uploaded upgrade bundle information\n  nsxt_upload_upgrade_bundle_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      component_type: \"host\"\n'''\n\nRETURN = '''# '''\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(component_type=dict(required=True, type='str', choices=['host', 'edge', 'mp']))\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  if module.params['component_type'] is None:\n    module.fail_json(msg='Error: parameter component_type not provided')\n  else:\n    component_type = module.params['component_type']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/upgrade/plan/%s/settings' % component_type.upper(),\n                         headers=dict(Accept='application/json'), url_username=mgr_username, \n                         url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error while retrieving bundle information. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n  main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_postchecks.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_postchecks\nshort_description: 'Execute post-upgrade checks'\ndescription: \"Run pre-defined checks to identify potential issues which can be \n              encountered after an upgrade. The results\n              of the checks are added to the respective upgrade units aggregate-info. The \n              progress and status of operation is part of upgrade status summary of \n              individual components.\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    component_type:\n        choices:\n            - host\n            - mp\n            - edge\n        description: \"Component type on which post upgrade is to be run.\"\n        required: true   \n'''\n\nEXAMPLES = '''\n- name: Runs post-upgrade checks\n  nsxt_upgrade_postchecks:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      component_type: 'mp'\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom csv import reader\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import get_attribute_from_endpoint, clean_and_get_params, get_upgrade_orchestrator_node\nfrom ansible.module_utils._text import to_native\n\ndef wait_for_post_upgrade_checks_to_execute(module, manager_url, endpoint, mgr_username,\n                                  mgr_password, validate_certs, component_type, \n                                  time_out=10800):\n  '''\n    params:\n    - endpoint: API endpoint.\n    - attribute_list: The attribute whose value should become the desired attribute value\n    - desired_attribute_value: The desired attribute value\n    \n    Function will wait till the attribute value derived from going deep to attribute list\n    becomes equal to desired_attribute_value.\n   '''\n  operation_time = 0\n  while True:\n    try:\n      (rc, resp) = request(manager_url + endpoint, headers=dict(Accept='application/json'),\n                           url_username=mgr_username, url_password=mgr_password, \n                           validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n       module.fail_json(msg=\"Failed while polling for post upgrade checks to complete. Error[%s].\" % to_native(err))\n    if resp.__contains__('results'):\n      flag = True\n      results = resp['results']\n      for result in results:\n        if result['post_upgrade_status']['status'] != 'COMPLETED' and \\\n           result['type'] == component_type.upper() and \\\n           result['upgrade_unit_count'] > 0 and \\\n           result['status'] != 'NOT_STARTED':\n          flag = False\n      if flag:\n        return None\n    time.sleep(15)\n    operation_time = operation_time + 15\n    if operation_time > time_out:\n      raise Exception('Operation timed out.')\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(timeout=dict(type='int', required=False),\n                      component_type=dict(required=True, choices=['mp', 'host', 'edge']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  timeout = module.params['timeout']\n  component_type= module.params['component_type']\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n\n  mgr_hostname = get_upgrade_orchestrator_node(module, mgr_hostname, mgr_username, \n                                            mgr_password, headers, validate_certs)\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  #if state == 'present':\n  # Runs post upgrade checks\n  if module.check_mode:\n    module.exit_json(changed=False, debug_out='Post upgrade checks will be executed.', \n                     id='Post upgrade checks')\n  try:\n    (rc, resp) = request(manager_url + '/upgrade/%s?action=execute_post_upgrade_'\n                        'checks' % component_type.upper(), data='', headers=headers,\n                        method='POST', url_username=mgr_username, \n                        url_password=mgr_password, validate_certs=validate_certs, \n                        ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg=\"Failed to execute post upgrade checks. Error[%s].\" % to_native(err))\n\n  try:\n    if timeout is None:\n      wait_for_post_upgrade_checks_to_execute(module, manager_url, '/upgrade/upgrade-unit-groups'\n                                             '/aggregate-info', mgr_username, mgr_password, \n                                             validate_certs, component_type)\n    else:\n      wait_for_post_upgrade_checks_to_execute(module, manager_url, '/upgrade/upgrade-unit-groups'\n                                             '/aggregate-info', mgr_username, mgr_password,\n                                             validate_certs, component_type, timeout)\n  except Exception as err:\n      module.fail_json(msg='Error while polling for execution of post upgrade'\n                             ' checks. Error [%s]' % to_native(err))\n  time.sleep(5)\n  changed = True\n  try:\n    (rc, resp) = request(manager_url+ '/upgrade/upgrade-unit-groups/aggregate-info', \n                         url_username=mgr_username, url_password=mgr_password, \n                         validate_certs=validate_certs)\n  except Exception as err:\n    module.fail_json(msg='Post upgrade checks were executed successfully but error'\n                  ' occured while retrieving the results. Error [%s]' % (to_native(err)))\n  module.exit_json(changed=changed, message='Post upgrade checks are performed successfully:\\n'\n                     '----------------------------\\n' + str(resp))\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_pre_post_checks_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_pre_post_checks_facts\nshort_description: 'Get the pre and post upgrade checks'\ndescription: 'Get the pre and post upgrade checks'\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: Get the pre upgrade and post upgrade checks\n  nsxt_upgrade_pre_post_checks_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/upgrade/upgrade-checks-info',\n                         headers=dict(Accept='application/json'), url_username=mgr_username, \n                         url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error while retrieving pre and post upgrade checks. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n  main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_prechecks.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_prechecks\nshort_description: 'Execute pre-upgrade checks'\ndescription: \"Run pre-defined checks to identify potential issues which can be \n              encountered during an upgrade or can cause an upgrade to fail. The results \n              of the checks are added to the respective upgrade units aggregate-info. The \n              progress and status of operation is part of upgrade status summary of \n              individual components.\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    timeout:\n        description: 'Timeout while polling for prechecks to complete'\n        required: false\n        type: int\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to run pre upgrade checks.\n                      'absent' is used to abort preupgrade checks.\"\n        required: true   \n'''\n\nEXAMPLES = '''\n- name: Runs and aborts pre-upgrade checks\n  nsxt_upgrade_prechecks:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      state: 'present'\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom csv import reader\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import get_attribute_from_endpoint, clean_and_get_params, get_upgrade_orchestrator_node\nfrom ansible.module_utils._text import to_native\n\ndef wait_for_pre_upgrade_checks_to_execute(module, manager_url, endpoint, mgr_username,\n                                  mgr_password, validate_certs, time_out=10800):\n  '''\n    params:\n    - endpoint: API endpoint.\n    - attribute_list: The attribute whose value should become the desired attribute value\n    - desired_attribute_value: The desired attribute value\n    \n    Function will wait till the attribute value derived from going deep to attribute list\n    becomes equal to desired_attribute_value.\n   '''\n  operation_time = 0\n  while True:\n    try:\n      (rc, resp) = request(manager_url + endpoint, headers=dict(Accept='application/json'),\n                           url_username=mgr_username, url_password=mgr_password, \n                           validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n       pass\n    if resp.__contains__('component_status'):\n      flag = True\n      component_statuses = resp['component_status']\n      for component_status in component_statuses:\n        if component_status['pre_upgrade_status']['status'] == 'ABORTED':\n          module.exit_json(changed= False, message='Pre upgrade checks started to run,'\n                                                   ' but aborted before they could finish.')\n        if component_status['pre_upgrade_status']['status'] != 'COMPLETED':\n          flag = False\n      if flag:\n        return None\n    time.sleep(15)\n    operation_time = operation_time + 15\n    if operation_time > time_out:\n      raise Exception('Operation timed out.')\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(timeout=dict(type='int', required=False),\n                      state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  upgrade_prechecks_params = clean_and_get_params(module.params.copy(), ['timeout'])\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  timeout = module.params['timeout']\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n  \n  mgr_hostname = get_upgrade_orchestrator_node(module, mgr_hostname, mgr_username, \n                                            mgr_password, headers, validate_certs)\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  if state == 'present':\n    # Runs pre upgrade checks\n    if module.check_mode:\n      module.exit_json(changed=False, debug_out='Pre upgrade checks will be executed.', \n                       id='Pre upgrade checks')\n    request_data = json.dumps(upgrade_prechecks_params)\n    try:\n      (rc, resp) = request(manager_url + '/upgrade?action=execute_pre_upgrade_checks', \n                           data='', headers=headers, method='POST', \n                           url_username=mgr_username, url_password=mgr_password, \n                           validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg=\"Failed to execute pre upgrade checks. Error[%s].\" % to_native(err))\n\n    try:\n      if timeout is None:\n        wait_for_pre_upgrade_checks_to_execute(module, manager_url, '/upgrade/status-summary',\n                          mgr_username, mgr_password, validate_certs)\n      else:\n        wait_for_pre_upgrade_checks_to_execute(module, manager_url, '/upgrade/status-summary',\n                          mgr_username, mgr_password, validate_certs, timeout)\n    except Exception as err:\n        module.fail_json(msg='Error while polling for execution of pre upgrade'\n                             ' checks. Error [%s]' % to_native(err))\n    time.sleep(5)\n    changed = False\n    try:\n      (rc, resp) = request(manager_url+ '/upgrade/pre-upgrade-checks/failures',\n                           url_username=mgr_username, url_password=mgr_password, \n                           validate_certs=validate_certs)\n    except Exception as err:\n      module.fail_json(msg='Pre upgrade checks were executed successfully but error'\n                  ' occured while retrieving the results. Error [%s]' % (to_native(err)))\n    # Fail module in case any pre upgrade check fails\n    prechecks_failure = False\n    if  'results' in resp:\n      for result in resp['results']:\n        if  'type' in result and result['type'] == 'FAILURE':\n          prechecks_failure = True\n    if prechecks_failure:\n      module.fail_json(msg='Pre upgrade checks are performed successsfully. Found errors. '\n                            'Thus, you cannot proceed. To get full report run upgrade groups '\n                            'facts module. Precheck results: %s' % str(resp))\n    module.exit_json(changed=changed, message='Pre upgrade checks are performed successfully:'\n                     ' Failures are listed. To get full report run upgrade groups '\n                     'facts module.' + str(resp))\n  elif state == 'absent':\n    # Aborts pre upgrade checks\n    try:\n       (rc, resp) = request(manager_url + '/upgrade?action=abort_pre_upgrade_checks', \n                            data='', headers=headers, method='POST',\n                            url_username=mgr_username, url_password=mgr_password, \n                            validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg=\"Failed to abort running pre upgrade checks. Error[%s].\" % to_native(err))\n\n    time.sleep(5)\n    module.exit_json(changed=True, message=\"Upgrade prechecks are aborted.\")\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_run.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_run\nshort_description: 'Start the upgrade'\ndescription: 'Upgrade will start as per the upgrade plan.'\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    paused_upgrade:\n        description: 'Mode of upgrade'\n        required: true\n        type: bool\n'''\n\nEXAMPLES = '''\n- name: Runs the upgrade\n  nsxt_upgrade_run:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      paused_upgrade: True\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import get_attribute_from_endpoint, clean_and_get_params, get_upgrade_orchestrator_node\nfrom ansible.module_utils._text import to_native\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.upgrade_reverse_order import trigger_upgrade_reverse_order\n\ndef get_upgrade_status(module, manager_url, mgr_username, mgr_password, validate_certs):\n  '''\n  Get the current status of upgrade at the start.\n  Doesn't upgrade if any component is in progress \n  or system is already upgraded.\n  '''\n  no_of_checks = 0\n  while True:\n    endpoint = \"/upgrade/upgrade-unit-groups?sync=true\"\n    call_get_sync(manager_url, endpoint, mgr_username, mgr_password, validate_certs)\n    upgrade_status = get_attribute_from_endpoint(module, manager_url, '/upgrade/status-summary',\n                     mgr_username, mgr_password, validate_certs, 'overall_upgrade_status', \n                     False)\n    no_of_checks = no_of_checks + 1\n    if upgrade_status == 'IN_PROGRESS' or upgrade_status == 'PAUSING':\n      if no_of_checks > 2:\n        module.fail_json(msg='Upgrade is in state: %s, can\\'t continue' % upgrade_status)\n    elif upgrade_status == 'SUCCESS':\n      module.exit_json(changed=False, message='Upgrade state is SUCCESS. No need to'\n                    ' continue.')\n    else:\n      return upgrade_status\n    time.sleep(20)\n\n\ndef call_get_sync(managerUrl, endpoint, mgrUsername, mgrPassword, validateCerts):\n    request(managerUrl + endpoint, method='GET', url_username=mgrUsername, url_password=mgrPassword,\n            validate_certs=validateCerts, ignore_errors=True)\n\n\ndef decide_next_step(module, manager_url, mgr_username, mgr_password,\n                     validate_certs, can_continue, is_failed):\n  '''\n  params:\n  - can_continue: if upgrade can be continued \n  - is_failed: Is there any component Failure\n  return:\n  - Decides the next operation to be done based on \n    can_continue and is_failed values \n  '''\n  if can_continue and is_failed:\n    return\n  elif can_continue and not is_failed:\n    return\n  elif not can_continue and is_failed:\n    raise Exception('Upgrade failed. Please run upgrade status summary'\n                    ' to see the reason of upgrade failure.')\n  else:\n    time.sleep(15)\n    try:\n      upgrade_status = get_attribute_from_endpoint(module, manager_url, '/upgrade/summary',\n                        mgr_username, mgr_password, validate_certs, 'upgrade_status',\n                        False)\n    except Exception as err:\n      return\n    if upgrade_status == 'SUCCESS':\n      module.exit_json(changed=True, message='System has been upgraded successfully!!!')\n    elif upgrade_status == 'IN_PROGRESS' or upgrade_status == 'PAUSING' or upgrade_status == 'PAUSED':\n      return\n    else:\n      module.fail_json(msg='All components till last one are upgraded. Still upgrade status'\n        ' is %s. Please run upgrade status summary to see the reason.' % upgrade_status)\n\n\ndef check_continuity(module, manager_url, mgr_username, mgr_password, validate_certs):\n  '''\n  Returns:\n  Based on the output of upgrade status summary API, gets the\n  checks and returns if upgrade can be continued and\n  if there is any component fail in the upgrade\n  '''\n  try:\n    component_status_list = get_attribute_from_endpoint(module, manager_url, \n                          '/upgrade/status-summary', mgr_username, mgr_password,\n                          validate_certs, 'component_status', False)\n  except Exception as err:\n    can_continue = True\n    is_failed = True\n    return can_continue, is_failed\n  try:\n    can_continue = True\n    for component_status in component_status_list:\n      if component_status['status'] == 'IN_PROGRESS' or \\\n         component_status['status'] == 'PAUSING':\n        can_continue = False\n        break\n    if not can_continue:\n      return can_continue, False\n    else:\n      is_failed = False\n      found_not_started = False\n      for component_status in component_status_list[::-1]:\n        if component_status['status'] == 'NOT_STARTED':\n          found_not_started = True\n        elif component_status['status'] == 'PAUSED':\n          can_continue = True\n          is_failed = False\n          return can_continue, is_failed\n        elif component_status['status'] == 'SUCCESS':\n          if not found_not_started:\n            can_continue = False\n            is_failed = False\n            return can_continue, is_failed\n          else:\n            can_continue = True\n            is_failed = False\n            return can_continue, is_failed\n        elif component_status['status'] == 'FAILED':\n          can_continue = False\n          is_failed = True\n          return can_continue, is_failed\n        elif component_status['status'] == 'IN_PROGRESS' or \\\n        component_status['status'] == 'PAUSING':\n          can_continue = False\n          is_failed = False\n          return can_continue, is_failed\n        else:\n          return True, True\n  except Exception as err:\n    can_continue = True\n    is_failed = True\n    return can_continue, is_failed\n  \ndef fetch_target_version(module, manager_url, mgr_username, mgr_password,\n                     validate_certs):\n  try:\n    target_version = get_attribute_from_endpoint(module, manager_url, '/upgrade/summary',\n                      mgr_username, mgr_password, validate_certs, 'target_version',\n                      False)\n  except Exception as err:\n    return\n  return target_version\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(paused_upgrade=dict(type='bool', required=True))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  paused_upgrade = module.params['paused_upgrade']\n  \n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n  \n  mgr_hostname = get_upgrade_orchestrator_node(module, mgr_hostname, mgr_username, \n                                            mgr_password, headers, validate_certs)\n  \n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  target_version = fetch_target_version(module, manager_url, mgr_username, mgr_password,\n                     validate_certs)\n  \n  if int(target_version[0])>=9 :\n    trigger_upgrade_reverse_order(module, mgr_hostname, mgr_username, mgr_password, validate_certs)\n\n  if module.check_mode:\n    if paused_upgrade:\n      module.exit_json(changed=False, debug_out='NSX-T will upgrade with pauses.')\n    else:\n      module.exit_json(changed=False, debug_out='NSX-T will upgrade without pauses.')\n\n  # If paused_upgrade is not true i.e auto mode\n  if not paused_upgrade:\n    while True:\n      upgrade_status = get_upgrade_status(module, manager_url, mgr_username,\n                                          mgr_password, validate_certs)\n      if upgrade_status == 'NOT_STARTED':\n        try:\n          (rc, resp) = request(manager_url+ '/upgrade/plan?action=start', \n                         data='', headers=headers, method='POST', \n                         url_username=mgr_username, url_password=mgr_password, \n                         validate_certs=validate_certs, ignore_errors=True)\n        except Exception as err:\n          module.fail_json(msg=\"Failed while upgrading. Error[%s].\" % to_native(err))\n      else:\n        try:\n          (rc, resp) = request(manager_url+ '/upgrade/plan?action=continue', \n                         data='', headers=headers, method='POST', \n                         url_username=mgr_username, url_password=mgr_password, \n                         validate_certs=validate_certs, ignore_errors=True)\n        except Exception as err:\n          module.fail_json(msg=\"Failed while upgrading. Error[%s].\" % to_native(err))\n\n      time.sleep(10)\n      while True:\n        try:\n          can_continue, is_failed = check_continuity(module, manager_url, mgr_username,\n                                                     mgr_password, validate_certs)\n          decide_next_step(module, manager_url, mgr_username, mgr_password, \n                           validate_certs, can_continue, is_failed)\n          if can_continue and not is_failed:\n            break\n          time.sleep(10)\n        except Exception as err:\n          module.fail_json(msg='Upgrade failed. Error: [%s]' % to_native(err))\n  else:\n    # Paused upgrade i.e manual mode\n    upgrade_status = get_upgrade_status(module, manager_url, mgr_username,\n                                          mgr_password, validate_certs)\n    if upgrade_status == 'NOT_STARTED':\n      try:\n        (rc, resp) = request(manager_url+ '/upgrade/plan?action=start', \n                     data='', headers=headers, method='POST', \n                     url_username=mgr_username, url_password=mgr_password, \n                     validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n        module.fail_json(msg=\"Failed while upgrading. Error[%s].\" % to_native(err))\n    else:\n      try:\n        (rc, resp) = request(manager_url+ '/upgrade/plan?action=continue', \n                     data='', headers=headers, method='POST', \n                     url_username=mgr_username, url_password=mgr_password, \n                     validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n        module.fail_json(msg=\"Failed while upgrading. Error[%s].\" % to_native(err))\n    time.sleep(10)\n    while True:\n      try:\n        can_continue, is_failed = check_continuity(module, manager_url, mgr_username,\n                                                   mgr_password, validate_certs)\n        decide_next_step(module, manager_url, mgr_username, mgr_password, \n                         validate_certs, can_continue, is_failed)\n        if can_continue and not is_failed:\n          break\n        time.sleep(10)\n      except Exception as err:\n        module.fail_json(msg='Upgrade failed. Error: [%s]' % to_native(err))\n    module.exit_json(changed=True, message='A component has been upgraded successfully.'\n                                           ' Whole system is not. Please run the module'\n                                           ' again till the time whole system is'\n                                           ' not upgraded.')\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_status_summary_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_status_summary_facts\nshort_description: 'Get the upgrade groups information'\ndescription: 'Get the upgrade groups information'\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: Get upgrade status summary\n  nsxt_upgrade_status_summary_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url + '/upgrade/status-summary',\n                         headers=dict(Accept='application/json'), url_username=mgr_username, \n                         url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error while retrieving upgrade status summary '\n                         'information. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\n\nif __name__ == '__main__':\n  main()"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_uc.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_uc\nshort_description: 'Upgrade the upgrade coordinator'\ndescription: \"Upgrade the upgrade coordinator\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: Upgrade UC\n  nsxt_upgrade_uc:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import wait_for_operation_to_execute, get_upgrade_orchestrator_node\nfrom ansible.module_utils._text import to_native\n\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n\n  mgr_hostname = get_upgrade_orchestrator_node(module, mgr_hostname, mgr_username, \n                                            mgr_password, headers, validate_certs)\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  # Upgrade UC\n  if module.check_mode:\n    module.exit_json(changed=False, debug_out='Upgrade Coordinator '\n                     'will be upgraded.', id=mgr_hostname)\n\n  try:\n    (rc, resp) = request(manager_url+ '/upgrade?action=upgrade_uc', data='',\n                         headers=headers, method='POST', url_username=mgr_username,\n                         url_password=mgr_password, validate_certs=validate_certs,\n                         ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Failed to upgrade UC. Error[%s].' % to_native(err))\n\n  time.sleep(5)\n\n  try:\n    wait_for_operation_to_execute(manager_url, '/upgrade/uc-upgrade-status', \n                                  mgr_username, mgr_password, validate_certs, \n                                  ['state'], ['SUCCESS'], ['FAILED'])\n  except Exception as err:\n    module.fail_json(msg='Error while upgrading UC. Error [%s]' % to_native(err))\n  module.exit_json(changed=True, result=resp, message='UC is upgraded'\n                                                      ' successfully.')\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_uc_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_uc_facts\nshort_description: Get upgrade-coordinator upgrade status \ndescription: Get upgrade-coordinator upgrade status \n\nversion_added: \"2.7\"\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: Gets UC upgrade status\n  nsxt_upgrade_uc_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/upgrade/uc-upgrade-status', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing UC upgrade status. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_upload_mub.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upgrade_upload_mub\nshort_description: 'Uploads upgrade mub'\ndescription: \"Uploads upgrade mub\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    file:\n        description: 'The path of the mub file'\n        required: false\n        type: str\n    url:\n        description: 'URL of MUB file'\n        required: false\n        type: str\n'''\n\nEXAMPLES = '''\n- name: Upload MUB\n  upload_mub:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      url: \"https://file-server.com/file.mub\"\n'''\n\nRETURN = '''# '''\nimport atexit\nimport mmap\nimport os\n\nimport json\nimport time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import wait_for_operation_to_execute\nfrom ansible.module_utils._text import to_native\n\n\ndef get_upload_mub_params(args=None):\n    args_to_remove = ['username', 'password', 'port', 'hostname', 'validate_certs', 'timeout']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value is None:\n            args.pop(key, None)\n    return args\n\ndef get_mgr_ip_upgrade_enabled(module, mgr_url, mgr_username, mgr_password,\n                               headers, validate_certs):\n    try:\n        (rc, resp) = request(mgr_url + '/node/services/install-upgrade',\n               headers=headers, url_username=mgr_username, url_password=mgr_password, \n                             validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n        module.fail_json(changed=True, msg='Error getting ip address where '\n                        'upgrade is enabled. Error: {}'.format(err))\n    return resp['service_properties']['enabled_on'];\n\ndef wait_till_upload_done(module, bundle_id, mgr_url, mgr_username, mgr_password, \n                          headers, validate_certs):\n    try:\n       while True:\n         (rc, resp) = request(mgr_url + '/upgrade/bundles/%s/upload-status'% bundle_id,\n                             headers=headers, url_username=mgr_username, \n                             url_password=mgr_password, validate_certs=validate_certs, \n                             ignore_errors=True)\n         if resp['status'] == 'FAILED':\n             module.fail_json(msg='Failed to upload upgrade bunlde. Error: %s' % \n                              resp['detailed_status'])\n         if resp['status'] == 'SUCCESS':\n             time.sleep(5)\n             return\n    except Exception as err:\n          module.fail_json(changed=True, msg=\"Error: %s\" % err)\n\ndef upload_mub(module, mgr_url, mgr_username, mgr_password, validate_certs, request_data, \n               headers, ip_address, timeout=10800):\n    endpoint = '/upgrade/bundles'\n    mub_type = 'url'\n    #headers = {}\n    if module.params['file'] is not None:\n        mub_type = 'file'\n        endpoint = endpoint +'?action=upload'\n    if mub_type == 'file':\n        file_path = module.params['file']\n        try:\n            file_data = open(file_path, 'rb')\n            atexit.register(file_data.close)\n        except Exception as e:\n            module.fail_json(msg='failed to open mub file %s Error: %s' %\n                             (file_path, to_native(e)))\n\n        if os.stat(file_path).st_size == 0:\n            request_data = ''\n        else:\n            request_data = mmap.mmap(file_data.fileno(), 0, access=mmap.ACCESS_READ)\n            atexit.register(request_data.close)\n\n\n        from urllib3 import encode_multipart_formdata\n        from urllib3.fields import RequestField\n\n        with open(file_path, 'rb') as src_file:\n             rf = RequestField('file', src_file.read(), os.path.basename(src_file.name))\n             rf.make_multipart()\n             body, content_type = encode_multipart_formdata([rf])\n  \n        headers['Content-Type'] = content_type\n        headers['Content-length'] = len(body)\n\n    if mub_type == 'url':\n      body = request_data\n\n    try:\n        (rc, resp) = request(mgr_url + endpoint, data=body, headers=headers, \n                             method='POST', url_username=mgr_username, \n                             url_password=mgr_password, validate_certs=validate_certs, \n                             ignore_errors=True)\n        if rc == 200:\n            bundle_id = 'latest'#resp['bundle_id']\n            headers = dict(Accept=\"application/json\")\n            headers['Content-Type'] = 'application/json'\n            try:\n                wait_for_operation_to_execute(mgr_url, \n                    '/upgrade/bundles/%s/upload-status'% bundle_id, \n                    mgr_username, mgr_password, validate_certs, \n                    ['status'], ['SUCCESS'], ['FAILED'])\n            except Exception as err:\n                module.fail_json(msg='Error while uploading upgrade bundle. Error [%s]' % to_native(err))\n            module.exit_json(changed=True, ip_address=ip_address, response=resp, \n            message='The upgrade bundle %s got uploaded successfully.' % module.params[mub_type])\n        else:\n            module.fail_json(msg='Failed to run upload mub. response code: {}'\n                                 ' response: {}'.format(rc, resp))\n    except Exception as err:\n        module.fail_json(changed=True, msg=\"Error: {}\".format(err))\n\n\ndef main():\n    argument_spec = vmware_argument_spec()\n    argument_spec.update(url=dict(type='str'),\n                         file=dict(type='str'),\n                         timeout=dict(type='int', required=False))\n    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, \n                           required_one_of=[('url', 'file')])\n    upgrade_params = get_upload_mub_params(module.params.copy())\n\n    mgr_hostname = module.params['hostname']\n    mgr_username = module.params['username']\n    mgr_password = module.params['password']\n    validate_certs = module.params['validate_certs']\n    timeout = module.params['timeout']\n    manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n    request_data = json.dumps(upgrade_params)\n    node_ip_address = get_mgr_ip_upgrade_enabled(module, manager_url, mgr_username, mgr_password,\n                                                 headers, validate_certs)\n    update_node_url = 'https://{}/api/v1'.format(node_ip_address)\n    if timeout is not None:\n        upload_mub(module, update_node_url, mgr_username, mgr_password, validate_certs, request_data, \n               headers, node_ip_address, timeout)\n    else:\n        upload_mub(module, update_node_url, mgr_username, mgr_password, validate_certs, request_data, \n               headers, node_ip_address)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_upgrade_upload_mub_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_upload_upgrade_bundle_facts\nshort_description: 'Get uploaded upgrade bundle information.'\ndescription: \"Get uploaded upgrade bundle information.\"\nversion_added: '2.7'\nauthor: 'Kommireddy Akhilesh'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    bundle_id:\n        description: 'Uploaded bundle ID'\n        required: true\n        type: str\n'''\n\nEXAMPLES = '''\n- name: Get uploaded upgrade bundle information\n  nsxt_upload_upgrade_bundle_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      bundle_id: \"2500014166034\"\n'''\n\nRETURN = '''# '''\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(bundle_id=dict(required=True, type='str'))\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  if module.params['bundle_id'] is None:\n    module.fail_json(msg='Error: parameter bundle ID not provided')\n  else:\n    bundle_id = module.params['bundle_id']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/upgrade/bundles/%s/upload-status' % bundle_id, headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error while retrieving bundle information. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n  main()\n"
  },
  {
    "path": "plugins/modules/nsxt_uplink_profiles.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_uplink_profiles\nshort_description: Create a Hostswitch Profile\ndescription: Creates a hostswitch profile. The resource_type is required. For uplink\n              profiles, the teaming and policy parameters are required. By default, the\n              mtu is 1600 and the transport_vlan is 0. The supported MTU range is 1280\n              through 9000.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n    display_name:\n        description: Display name\n        required: true\n        type: str\n    description:\n        description: Description of the resource\n        required: false\n        type: str\n    enabled:\n        description: 'The enabled property specifies the status of NIOC feature.\n                      When enabled is set to true, NIOC feature is turned on and\n                      the bandwidth allocations specified for the traffic resources\n                      are enforced. When enabled is set to false, NIOC feature\n                      is turned off and no bandwidth allocation is guaranteed.\n                      By default, enabled will be set to true.'\n        required: false\n        type: boolean\n    extra_configs:\n        description: list of extra configs\n        required: false\n        type: array of ExtraConfig\n    host_infra_traffic_res:\n        description: 'host_infra_traffic_res specifies bandwidth allocation for\n                      various traffic resources.'\n        required: false\n        type: array of ResourceAllocation\n    lags:\n        description: list of LACP group\n        required: false\n        type: array of Lag\n    mtu:\n        description: Maximum Transmission Unit used for uplinks\n        required: false\n        type: int\n    named_teamings:\n        description: List of named uplink teaming policies that can be used by logical switches\n        required: false\n        type: array of NamedTeamingPolicy\n    overlay_encap:\n        description: The protocol used to encapsulate overlay traffic\n        required: false\n        type: str\n    required_capabilities:\n        description: None\n        required: false\n        type: list\n    resource_type:\n        choices:\n        - UplinkHostSwitchProfile\n        description: Supported HostSwitch profiles.\n        required: true\n        type: str\n    send_enabled:\n        description: Enabled or disabled sending LLDP packets\n        required: false\n        type: boolean\n    tags:\n        description: Opaque identifier meaninful to API user\n        required: false\n        type: Array of Tag\n    state:\n        choices:\n        - present\n        - absent\n        description: \"State can be either 'present' or 'absent'. \n                    'present' is used to create or update resource. \n                    'absent' is used to delete resource.\"\n        required: true\n    teaming:\n        active_list:\n            description: List of Uplinks used in active list\n            required: true\n            type: array of Uplink\n        description: Default TeamingPolicy associated with this UplinkProfile\n        policy:\n            description: Teaming policy\n            required: true\n            type: str\n        required: true\n        standby_list:\n            description: List of Uplinks used in standby list\n            required: false\n            type: array of Uplink\n        type: dict\n    transport_vlan:\n        description: VLAN used for tagging Overlay traffic of associated HostSwitch\n        required: false\n        type: int\n    \n'''\n\nEXAMPLES = '''\n- name: Create a Hostswitch Profile\n  nsxt_uplink_profiles:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      display_name: \"uplinkProfile1\",\n      mtu: 1600,\n      resource_type: \"UplinkHostSwitchProfile\",\n      teaming:\n        active_list:\n        - uplink_name: \"uplink-1\"\n          uplink_type: PNIC\n        policy: FAILOVER_ORDER\n      transport_vlan: 0,\n      state: \"present\",\n'''\n\nRETURN = '''# '''\n\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef get_profile_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef get_host_switch_profiles(module, manager_url, mgr_username, mgr_password, validate_certs):\n    try:\n      (rc, resp) = request(manager_url+ '/host-switch-profiles', headers=dict(Accept='application/json'),\n                      url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n    except Exception as err:\n      module.fail_json(msg='Error accessing host profiles. Error [%s]' % (to_native(err)))\n    return resp\n\ndef get_uplink_profile_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, display_name):\n    host_switch_profiles = get_host_switch_profiles(module, manager_url, mgr_username, mgr_password, validate_certs)\n    for host_switch_profile in host_switch_profiles['results']:\n        if host_switch_profile.__contains__('display_name') and host_switch_profile['display_name'] == display_name:\n            return host_switch_profile\n    return None\n\ndef id_exist_in_list_dict_obj(key, list_obj1, list_obj2):\n    all_id_presents = False\n    if len(list_obj1) != len(list_obj2):\n        return all_id_presents\n    for dict_obj1 in list_obj1:\n        if dict_obj1.__contains__(key):\n            for dict_obj2 in list_obj2:\n                if dict_obj2.__contains__(key) and dict_obj1[key] == dict_obj2[key]:\n                    all_id_presents = True\n                    continue\n            if not all_id_presents:\n                return False\n    return True\ndef cmp_dict(dict1, dict2): # dict1 contain dict2\n    #print dict2\n    for k2, v2 in dict2.items():\n        found = False\n        if k2 not in dict1:\n            continue\n        if type(v2) != list and dict1[k2] != dict2[k2]:\n            return False\n            \n        for obj2 in v2:\n            for obj1 in dict1[k2]:\n                if all(item in obj1.items() for item in obj2.items()):\n                           found = True\n        if not found:\n            return False\n    return True\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, profile_params):\n    existing_profile = get_uplink_profile_from_display_name(module, manager_url, mgr_username, mgr_password, validate_certs, profile_params['display_name'])\n    if existing_profile is None:\n        return False\n    if existing_profile.__contains__('mtu') and profile_params.__contains__('mtu') and \\\n        existing_profile['mtu'] != profile_params['mtu']:\n        return True\n    if existing_profile.__contains__('transport_vlan') and profile_params.__contains__('transport_vlan') and \\\n        existing_profile['transport_vlan'] != profile_params['transport_vlan']:\n        return True\n    if existing_profile.__contains__('lags') and not profile_params.__contains__('lags'):\n        return True\n    if not existing_profile.__contains__('lags') and profile_params.__contains__('lags'):\n        return True\n    if profile_params.__contains__('lags') and profile_params['lags']:\n       existing_lags = existing_profile['lags']\n       new_lags = profile_params['lags']\n       sorted_existing_lags = sorted(existing_lags, key = lambda i: i['name'])\n       sorted_new_lags = sorted(new_lags, key = lambda i: i['name'])\n       if len(sorted_existing_lags) != len(sorted_new_lags):\n          return True\n       both_lags_same = True\n       for i in range(len(sorted_existing_lags)):\n           diff_obj = {k: sorted_existing_lags[i][k] for k in sorted_existing_lags[i] if k in sorted_new_lags[i] and sorted_existing_lags[i][k] != sorted_new_lags[i][k]}\n           del diff_obj['uplinks']\n           if not cmp_dict(diff_obj, sorted_new_lags[i]):\n              both_lags_same = False\n       if not both_lags_same:\n          return True\n    if profile_params.__contains__('named_teamings'):\n       existing_teamings = existing_profile['named_teamings']\n       new_teamings = profile_params['named_teamings']\n       sorted_existing_teamings = sorted(existing_teamings, key = lambda i: i['name'])\n       sorted_new_teamings = sorted(new_teamings, key = lambda i: i['name'])\n       if len(sorted_existing_teamings) != len(sorted_new_teamings):\n          return False\n       both_teamings_same = True\n       for i in range(len(sorted_existing_teamings)):\n           diff_obj = {k: sorted_existing_teamings[i][k] for k in sorted_existing_teamings[i] if k in sorted_new_teamings[i] and sorted_existing_teamings[i][k] != sorted_new_teamings[i][k]}\n           if not cmp_dict(diff_obj, sorted_new_teamings[i]):\n              both_teamings_same = False\n       if not both_teamings_same:\n          return True\n    return False\n  \n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(display_name=dict(required=True, type='str'),\n                        transport_vlan=dict(required=False, type='int'),\n                        description=dict(required=False, type='str'),\n                        enabled=dict(required=False, type='boolean'),\n                        host_infra_traffic_res=dict(required=False, type='list'),\n                        overlay_encap=dict(required=False, type='str'),\n                        named_teamings=dict(required=False, type='list'),\n                        mtu=dict(required=False, type='int'),\n                        required_capabilities=dict(required=False, type='list'),\n                        send_enabled=dict(required=False, type='boolean'),\n                        extra_configs=dict(required=False, type='list'),\n                        teaming=dict(required=True, type='dict',\n                        policy=dict(required=True, type='str'),\n                        standby_list=dict(required=False, type='list'),\n                        active_list=dict(required=True, type='list')),\n                        lags=dict(required=False, type='list'),\n                        tags=dict(required=False, type='list'),\n                        resource_type=dict(required=True, type='str', choices=['UplinkHostSwitchProfile']),\n                        state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n  profile_params = get_profile_params(module.params.copy())\n  state = module.params['state']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n  display_name = module.params['display_name']\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  host_switch_profile_dict = get_uplink_profile_from_display_name (module, manager_url, mgr_username, mgr_password, validate_certs, display_name)\n  host_switch_profile_id, revision = None, None\n  if host_switch_profile_dict:\n    host_switch_profile_id = host_switch_profile_dict['id']\n    revision = host_switch_profile_dict['_revision']\n\n  if state == 'present':\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, profile_params)\n\n    if not updated:\n      # add the block\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(profile_params)), id='12345')\n      request_data = json.dumps(profile_params)\n      try:\n          if host_switch_profile_id:\n              module.exit_json(changed=False, id=host_switch_profile_id, message=\"Uplink profile with display_name %s already exist.\"% module.params['display_name'])\n\n          (rc, resp) = request(manager_url+ '/host-switch-profiles', data=request_data, headers=headers, method='POST',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to add host profile. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"host profile with display name %s created.\" % module.params['display_name'])\n    else:\n      if module.check_mode:\n          module.exit_json(changed=True, debug_out=str(json.dumps(profile_params)), id=host_switch_profile_id)\n\n      profile_params['_revision'] = revision # update current revision\n      request_data = json.dumps(profile_params)\n      id = host_switch_profile_id\n      try:\n          (rc, resp) = request(manager_url+ '/host-switch-profiles/%s' % id, data=request_data, headers=headers, method='PUT',\n                                url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n      except Exception as err:\n          module.fail_json(msg=\"Failed to update host profile with id %s. Request body [%s]. Error[%s].\" % (id, request_data, to_native(err)))\n\n      time.sleep(5)\n      module.exit_json(changed=True, id=resp[\"id\"], body= str(resp), message=\"host profile with id %s updated.\" % id)\n\n  elif state == 'absent':\n    # delete the array\n    id = host_switch_profile_id\n    if id is None:\n        module.exit_json(changed=False, msg='No host switch profile exist with display name %s' % display_name)\n    if module.check_mode:\n        module.exit_json(changed=True, debug_out=str(json.dumps(profile_params)), id=id)\n    try:\n        (rc, resp) = request(manager_url + \"/host-switch-profiles/%s\" % id, method='DELETE',\n                              url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to delete host profile with id %s. Error[%s].\" % (id, to_native(err)))\n\n    time.sleep(5)\n    module.exit_json(changed=True, object_name=id, message=\"host profile with id %s deleted.\" % id)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_uplink_profiles_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_uplink_profiles_facts\nshort_description: List Hostswitch Profiles\ndescription: Returns information about the configured hostswitch profiles. Hostswitch\n              profiles define networking policies for hostswitches (sometimes referred to\n              as bridges in OVS). Currently, only uplink teaming is supported. Uplink\n              teaming allows NSX to load balance traffic across different physical NICs\n              (PNICs) on the hypervisor hosts. Multiple teaming policies are supported,\n              including LACP active, LACP passive, load balancing based on source ID, and\n              failover order.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: List Hostswitch Profiles\n  nsxt_uplink_profiles_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\n\nimport json\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/host-switch-profiles', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing host switch profiles. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_vidm.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2021 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_vidm\nshort_description: 'Register a vIDM with NSX'\ndescription: \"Register a vIDM with NSX\"\nversion_added: '3.2'\nauthor: 'Kaushik Lele'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    client_id:\n        description: 'vIDM client id'\n        required: true\n        type: str\n    client_secret:\n        description: 'vIDM client secret'\n        required: false\n        type: str\n    host_name:\n        description: 'Fully Qualified Domain Name(FQDN) of vIDM'\n        required: false\n        type: str                \n    lb_enable:\n        description: 'Load Balancer enable flag'\n        required: false\n        type: bool\n    node_host_name:\n        description: \"Host name of the node redirected to\n            host name to use when creating the redirect URL for clients to follow after authenticating to vIDM\"\n        required: true\n        type: bool    \n    thumbprint:\n        description: \"vIDM certificate thumbprint\n            Hexadecimal SHA256 hash of the vIDM server's X.509 certificate\"\n        required: true\n        type: str            \n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true\n\n    \n'''\n\nEXAMPLES = '''\n- name: Register vIDM with NSX\n  nsxt_vidm:\n    hostname: \"10.192.167.137\"\n    username: \"admin\"\n    password: \"Admin!23Admin\"\n    validate_certs: False\n    client_id: \"OAuth2Client_NsxClientId\",\n    client_secret: \"23424234234234\"\n    host_name: \"lbhost_vidm.eng.vmware.com\",\n    lb_enable: False\n    node_host_name: \"jt-vidm.eng.vmware.com\"\n    thumbprint: \"898b75618e3e56615d53f987a720ff22b6381f4b85bec1eb973214ff7361f8b8\"\n    state: present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\nimport ssl\nimport socket\nimport hashlib\n\n\ndef get_vidm_params(args=None):\n    args_to_remove = ['state', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\n\ndef get_vidm(module, url, mgr_username, mgr_password, validate_certs):\n    try:\n        (rc, resp) = request(url, headers=dict(Accept='application/json'),\n                             url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                             ignore_errors=True)\n    except Exception as err:\n        module.fail_json(msg='Error accessing vidm details. Error [%s]' % (to_native(err)))\n    return resp\n\n\ndef get_vidm_from_client_id(module, url, mgr_username, mgr_password, validate_certs, client_id):\n    vidm = get_vidm(module, url, mgr_username, mgr_password, validate_certs)\n    if vidm['client_id'] == client_id:\n        return vidm\n    return None\n\n\ndef wait_till_create(module, url, mgr_username, mgr_password, validate_certs):\n    retry_counter = 0\n    try:\n        while True:\n\n            try:\n                (rc, resp) = request(url + '/status', headers=dict(Accept='application/json'),\n                                     url_username=mgr_username, url_password=mgr_password,\n                                     validate_certs=validate_certs, ignore_errors=True)\n                if resp['runtime_state'] != \"ALL_OK\":\n                    if retry_counter < 6:\n                        time.sleep(5)\n                        retry_counter = retry_counter + 1\n                    else:\n                        module.fail_json(\n                            msg='Failed to register vIDM. runtime state is : %s' % (str(resp[\"runtime_state\"])))\n                else:\n                    break;\n            except Exception as err:\n                # When registration is in progress and status is not yet accessible then it can throw error.\n                #  {'error_code': 36514, 'error_message': 'Error when requesting to verify VMware Identity Manager user access client',\n                # So retry is needed in error case as well.\n                if retry_counter < 6:\n                    retry_counter = retry_counter + 1\n                    time.sleep(5)\n                else:\n                    module.fail_json(msg='Failed to register vIDM. runtime state is : %s' % (to_native(err)))\n    except Exception as err:\n        module.fail_json(msg='Error accessing vIDM status. Error [%s]' % (to_native(err)))\n    return\n\n\ndef wait_till_delete(module, url, mgr_username, mgr_password, validate_certs):\n    retry_counter = 0\n    try:\n        while True:\n            (rc, resp) = request(url + '/status', headers=dict(Accept='application/json'),\n                                 url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                                 ignore_errors=True)\n            if resp['runtime_state'] != \"NOT_OK\" or resp['vidm_enable'] is not False:\n                if retry_counter < 6:\n                    time.sleep(10)\n                    retry_counter = retry_counter + 1\n                else:\n                    module.fail_json(msg='Failed to unregister vIDM. runtime state is : %s registration flag is : %s'\n                                         % (str(resp[\"runtime_state\"]), str(resp[\"vidm_enable\"])))\n            else:\n                break;\n    except Exception as err:\n        module.fail_json(msg='Error accessing vIDM status. Error [%s]' % (to_native(err)))\n    return\n\n\ndef check_for_update(existing_vidm, vidm_params):\n    if existing_vidm['client_id'] != vidm_params['client_id'] or \\\n            existing_vidm['host_name'] != vidm_params['host_name'] or \\\n            existing_vidm['client_id'] != vidm_params['client_id'] or \\\n            existing_vidm['lb_enable'] != vidm_params['lb_enable'] or \\\n            existing_vidm['node_host_name'] != vidm_params['node_host_name'] or \\\n            existing_vidm['thumbprint'] != vidm_params['thumbprint'] or \\\n            existing_vidm['vidm_enable'] != vidm_params['vidm_enable']:\n        return True\n\n    return False\n\n\ndef main():\n    argument_spec = vmware_argument_spec()\n    argument_spec.update(client_id=dict(required=True, type='str'),\n                         client_secret=dict(required=False, type='str'),\n                         host_name=dict(required=True, type='str'),\n                         lb_enable=dict(required=False, type='bool'),\n                         node_host_name=dict(required=True, type='str'),\n                         thumbprint=dict(required=True, type='str'),\n                         state=dict(required=True, choices=['present', 'absent']))\n\n    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n    vidm_params = get_vidm_params(module.params.copy())\n    state = module.params['state']\n    mgr_hostname = module.params['hostname']\n    mgr_username = module.params['username']\n    mgr_password = module.params['password']\n    validate_certs = module.params['validate_certs']\n    client_id = module.params['client_id']\n\n    manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n    vidm_api_url = manager_url + '/node/aaa/providers/vidm'\n    existing_vidm = get_vidm_from_client_id(module, vidm_api_url, mgr_username, mgr_password, validate_certs,\n                                            vidm_params['client_id'])\n    headers = dict(Accept=\"application/json\")\n    headers['Content-Type'] = 'application/json'\n\n    if state == 'present':\n        vidm_params[\"vidm_enable\"] = True\n        if existing_vidm is not None:\n            updated = check_for_update(existing_vidm, vidm_params)\n            if not updated:\n                module.exit_json(changed=False, id=vidm_params['client_id'],\n                                 message=\"vIDM with id %s is already enabled.\" % vidm_params['client_id'])\n\n        # vIDM not present or update. So call PUT API which is same for add and update vIDM\n        request_data = json.dumps(vidm_params)\n        if module.check_mode:\n            module.exit_json(changed=True, debug_out=str(request_data), id='12345')\n        try:\n            (rc, resp) = request(vidm_api_url, data=request_data, headers=headers, method='PUT',\n                                 url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                                 ignore_errors=True)\n        except Exception as err:\n            module.fail_json(\n                msg=\"Failed to register vIDM. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n        wait_till_create(module, vidm_api_url, mgr_username, mgr_password, validate_certs)\n\n        module.exit_json(changed=True, id=resp[\"client_id\"], body=str(resp),\n                         message=\"vIDM with client id %s registered.\" % resp[\"client_id\"])\n\n    elif state == 'absent':\n        if module.check_mode:\n            module.exit_json(changed=True, debug_out=str(json.dumps(vidm_params)), id=vidm_params['client_id'])\n\n        if existing_vidm is None:\n            module.exit_json(changed=False, id=vidm_params['client_id'],\n                             message=\"vIDM with client id %s was not registered.\" % vidm_params['client_id'])\n\n        # vIDM with given client_id is registered so unregister it\n        vidm_params['vidm_enable'] = False\n        request_data = json.dumps(vidm_params)\n\n        try:\n            (rc, resp) = request(vidm_api_url, data=request_data, headers=headers, method='PUT',\n                                 url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                                 ignore_errors=True)\n        except Exception as err:\n            module.fail_json(\n                msg=\"Failed to un-register vIDM. Request body [%s]. Error[%s].\" % (request_data, to_native(err)))\n\n        wait_till_delete(module, vidm_api_url, mgr_username, mgr_password, validate_certs)\n        module.exit_json(changed=True, id=vidm_params['client_id'], body=str(resp),\n                         message=\"vIDM with id %s is unregistered.\" % vidm_params['client_id'])\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_virtual_ip.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_virtual_ip\nshort_description: 'Sets and clears cluster virtual IP address'\ndescription: \"Sets the cluster virtual IP address. Note, all nodes in the management \n              cluster must be in the same subnet. If not, a 409 CONFLICT status is \n              returned. \"\nversion_added: '2.7'\nauthor: 'Rahul Raghuvanshi'\noptions:\n    hostname:\n        description: 'Deployed NSX manager hostname.'\n        required: true\n        type: str\n    username:\n        description: 'The username to authenticate with the NSX manager.'\n        required: true\n        type: str\n    password:\n        description: 'The password to authenticate with the NSX manager.'\n        required: true\n        type: str\n    virtual_ip_address:\n        description: 'Virtual IPv4 address to be set.'\n        required: true\n        type: str\n    virtual_ip6_address:\n        description: 'Virtual IPv6 address to be set.'\n        required: true\n        type: str\n    action:\n        choices:\n            - clear_virtual_ip\n            - clear_virtual_ip6\n        description: \"Action can be either 'clear_virtual_ip' or 'clear_virtual_ip6'.\n                      'clear_virtual_ip' is used to clear Virtual IPv4.\n                      'clear_virtual_ip6' is used to clear Virtual IPv6.\"\n        required: true only if state is absent\n    state:\n        choices:\n            - present\n            - absent\n        description: \"State can be either 'present' or 'absent'.\n                      'present' is used to create or update resource.\n                      'absent' is used to delete resource.\"\n        required: true   \n'''\n\nEXAMPLES = '''\n- name: Adds cluster virtual IP address\n  nsxt_virtual_ip:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n      virtual_ip_address: \"10.192.167.141\"\n      virtual_ip6_address: \"2620:124:6020:c308::10\"\n      action: clear_virtual_ip\n      state: present\n'''\n\nRETURN = '''# '''\n\nimport json, time\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.common_utils import check_if_valid_ip, get_attribute_from_endpoint\nfrom ansible.module_utils._text import to_native\n\ndef get_virtual_ip_params(args=None):\n    args_to_remove = ['state','action', 'username', 'password', 'port', 'hostname', 'validate_certs']\n    for key in args_to_remove:\n        args.pop(key, None)\n    for key, value in args.copy().items():\n        if value == None:\n            args.pop(key, None)\n    return args\n\ndef check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, vip_params):\n    if module.params['virtual_ip_address'] and module.params['virtual_ip6_address']:\n        existing_vip = get_attribute_from_endpoint(module, manager_url, '/cluster/api-virtual-ip', mgr_username, mgr_password, validate_certs, 'ip_address')\n        existing_vip6 = get_attribute_from_endpoint(module, manager_url, '/cluster/api-virtual-ip', mgr_username, mgr_password, validate_certs, 'ip6_address')\n        if existing_vip != vip_params['virtual_ip_address'] and existing_vip6 != vip_params['virtual_ip6_address']:\n            return True\n    elif module.params['virtual_ip_address']:\n        existing_vip = get_attribute_from_endpoint(module, manager_url, '/cluster/api-virtual-ip', mgr_username, mgr_password, validate_certs, 'ip_address')\n        if existing_vip != vip_params['virtual_ip_address']:\n            return True\n    elif module.params['virtual_ip6_address']:\n        existing_vip6 = get_attribute_from_endpoint(module, manager_url, '/cluster/api-virtual-ip', mgr_username, mgr_password, validate_certs, 'ip6_address')\n        if existing_vip6 != vip_params['virtual_ip6_address']:\n            return True\n    return False\n\ndef main():\n  argument_spec = vmware_argument_spec()\n  argument_spec.update(virtual_ip_address=dict(type='str'),\n                       virtual_ip6_address=dict(type='str'),\n                       action=dict(required_if=[('state', 'absent')], type='str', choices=['clear_virtual_ip', 'clear_virtual_ip6']),\n                       state=dict(required=True, choices=['present', 'absent']))\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True,  required_one_of=[('virtual_ip_address', 'virtual_ip6_address')])\n  virtual_ip_params = get_virtual_ip_params(module.params.copy())\n  state = module.params['state']\n  action = module.params['action']\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  headers = dict(Accept=\"application/json\")\n  headers['Content-Type'] = 'application/json'\n\n  if state == 'present':\n    # add virtual IP address\n    if module.params['virtual_ip_address']:\n        virtual_ip_address = virtual_ip_params['virtual_ip_address']\n        if not check_if_valid_ip(virtual_ip_address):\n            module.fail_json(msg=\"Virtual IP provided is invalid.\")\n    if module.params['virtual_ip6_address']:\n        virtual_ip6_address = virtual_ip_params['virtual_ip6_address']\n        if not check_if_valid_ip(virtual_ip6_address):\n            module.fail_json(msg=\"Virtual IP provided is invalid.\")\n\n    if module.check_mode:\n        module.exit_json(changed=False, debug_out=\"Cluster virtual IP would have been updated to %s\" % virtual_ip_params, id='12345')\n    updated = check_for_update(module, manager_url, mgr_username, mgr_password, validate_certs, virtual_ip_params)\n    if not updated:\n        if module.params['virtual_ip_address'] and module.params['virtual_ip6_address']:\n            module.exit_json(changed=False, message=\"Virtual IPs %s and %s are already set.\" % (virtual_ip_address, virtual_ip6_address))\n        elif module.params['virtual_ip_address']:\n            module.exit_json(changed=False, message=\"Virtual IP %s already set.\" % virtual_ip_address)\n        elif module.params['virtual_ip6_address']:\n            module.exit_json(changed=False, message=\"Virtual IP %s already set.\" % virtual_ip6_address)\n    else:\n        try:\n            if module.params['virtual_ip_address'] and module.params['virtual_ip6_address']:\n                (rc, resp) = request(manager_url + '/cluster/api-virtual-ip?action=set_virtual_ip&ip_address=%s&ip6_address=%s' % (virtual_ip_address, virtual_ip6_address), data='', headers=headers, method='POST', url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n            elif module.params['virtual_ip_address']:\n                (rc, resp) = request(manager_url + '/cluster/api-virtual-ip?action=set_virtual_ip&ip_address=%s' %virtual_ip_address, data='', headers=headers, method='POST', url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n            elif module.params['virtual_ip6_address']:\n                (rc, resp) = request(manager_url + '/cluster/api-virtual-ip?action=set_virtual_ip&ip6_address=%s' % virtual_ip6_address, data='', headers=headers, method='POST', url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n\n        except Exception as err:\n            module.fail_json(msg=\"Failed to add virtual IP address. Error[%s].\" % to_native(err))\n\n        time.sleep(5)\n        if module.params['virtual_ip_address'] and module.params['virtual_ip6_address']:\n            module.exit_json(changed=True, result=resp, message=\"Virtual IP address is set with ip addresses: %s and \"\n                                                                \"%s \" % (virtual_ip_address, virtual_ip6_address))\n        elif module.params['virtual_ip_address']:\n            module.exit_json(changed=True, result=resp, message=\"Virtual IP address is set with IPv4 address: %s \" % virtual_ip_address)\n        elif module.params['virtual_ip6_address']:\n            module.exit_json(changed=True, result=resp, message=\"Virtual IP address is set with IPv6 address: %s \" % virtual_ip6_address)\n\n\n\n  elif state == 'absent':\n    # delete virtual IP address\n    if action ==\"clear_virtual_ip\":\n        is_virtual_ip_set = True\n        virtual_ip_address = get_attribute_from_endpoint(module, manager_url, '/cluster/api-virtual-ip', mgr_username, mgr_password, validate_certs, 'ip_address')\n        if virtual_ip_address is None or virtual_ip_address == '0.0.0.0':\n            virtual_ip_address = \"Virtual IP address is not set\"\n            is_virtual_ip_set = False\n        if module.check_mode:\n            if not is_virtual_ip_set:\n                module.exit_json(changed=True, debug_out='Virtual IPv4 address is not set', id=virtual_ip_address)\n            else:\n                module.exit_json(changed=True, debug_out='Virtual IPv4 address is set to %s. Will be removed.'% virtual_ip_address, id=virtual_ip_address)\n\n        time.sleep(5)\n        if not is_virtual_ip_set:\n            module.exit_json(changed=False, object_name=\"Virtual IPv4 was not set before.\", message=\"Cleared cluster virtual IPv4 address.\")\n        try:\n            (rc, resp) = request(manager_url+ '/cluster/api-virtual-ip?action=clear_virtual_ip', data='', headers=headers, method='POST',\n                            url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n        except Exception as err:\n            module.fail_json(msg=\"Failed to clear virtual IPv4 address. Error[%s].\" % to_native(err))\n        module.exit_json(changed=True, object_name=virtual_ip_address, message=\"Cleared cluster virtual IPv4 address.\")\n\n    if action ==\"clear_virtual_ip6\":\n        is_virtual_ip6_set = True\n        virtual_ip6_address = get_attribute_from_endpoint(module, manager_url, '/cluster/api-virtual-ip', mgr_username,\n                                                         mgr_password, validate_certs, 'ip6_address')\n        if virtual_ip6_address is None or virtual_ip6_address == '::':\n            virtual_ip6_address = \"Virtual IPv6 address is not set\"\n            is_virtual_ip6_set = False\n        if module.check_mode:\n            if not is_virtual_ip6_set:\n                module.exit_json(changed=True, debug_out='Virtual IPv6 address is not set', id=virtual_ip6_address)\n            else:\n                module.exit_json(changed=True,\n                                 debug_out='Virtual IPv6 address is set to %s. Will be removed.' % virtual_ip6_address,\n                                 id=virtual_ip6_address)\n\n        time.sleep(5)\n        if not is_virtual_ip6_set:\n            module.exit_json(changed=False, object_name=\"Virtual IPv6 was not set before.\",\n                             message=\"Cleared cluster virtual IPv6 address.\")\n        try:\n            (rc, resp) = request(manager_url + '/cluster/api-virtual-ip?action=clear_virtual_ip6', data='',\n                                 headers=headers, method='POST',\n                                 url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs,\n                                 ignore_errors=True)\n        except Exception as err:\n            module.fail_json(msg=\"Failed to clear virtual IPv6 address. Error[%s].\" % to_native(err))\n        module.exit_json(changed=True, object_name=virtual_ip6_address, message=\"Cleared cluster virtual IPv6 address.\")\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "plugins/modules/nsxt_virtual_ip_facts.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_vitual_ip_facts\nshort_description: Read cluster virtual IP address\ndescription: Returns the configured cluster virtual IP address or null if not configured.\n\nversion_added: \"2.7\"\nauthor: Rahul Raghuvanshi\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        required: true\n        type: str\n    password:\n        description: The password to authenticate with the NSX manager.\n        required: true\n        type: str\n\n'''\n\nEXAMPLES = '''\n- name: Get all configured cluster virtual IP address\n  nsxt_virtual_ip_facts:\n      hostname: \"10.192.167.137\"\n      username: \"admin\"\n      password: \"Admin!23Admin\"\n      validate_certs: False\n'''\n\nRETURN = '''# '''\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.vmware_nsxt import vmware_argument_spec, request\nfrom ansible.module_utils._text import to_native\n\ndef main():\n  argument_spec = vmware_argument_spec()\n\n  module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)\n\n  mgr_hostname = module.params['hostname']\n  mgr_username = module.params['username']\n  mgr_password = module.params['password']\n  validate_certs = module.params['validate_certs']\n\n  manager_url = 'https://{}/api/v1'.format(mgr_hostname)\n\n  changed = False\n  try:\n    (rc, resp) = request(manager_url+ '/cluster/api-virtual-ip', headers=dict(Accept='application/json'),\n                    url_username=mgr_username, url_password=mgr_password, validate_certs=validate_certs, ignore_errors=True)\n  except Exception as err:\n    module.fail_json(msg='Error accessing virtual IP information. Error [%s]' % (to_native(err)))\n\n  module.exit_json(changed=changed, **resp)\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "plugins/modules/nsxt_vm_tags.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nANSIBLE_METADATA = {'metadata_version': '1.1',\n                    'status': ['preview'],\n                    'supported_by': 'community'}\n\nDOCUMENTATION = '''\n---\nmodule: nsxt_vm_tags\nshort_description: Update tags on NSXT VM\ndescription:\n    Update tags on NSXT VM\nversion_added: \"2.8\"\nauthor: Gautam Verma\noptions:\n    hostname:\n        description: Deployed NSX manager hostname.\n        required: true\n        type: str\n    username:\n        description: The username to authenticate with the NSX manager.\n        type: str\n    password:\n        description:\n            - The password to authenticate with the NSX manager.\n            - Must be specified if username is specified\n        type: str\n    validate_certs:\n        description: Enable server certificate verification.\n        type: bool\n        default: False\n    ca_path:\n        description: Path to the CA bundle to be used to verify host's SSL\n                     certificate\n        type: str\n    nsx_cert_path:\n        description: Path to the certificate created for the Principal\n                     Identity using which the CRUD operations should be\n                     performed\n        type: str\n    nsx_key_path:\n        description:\n            - Path to the certificate key created for the Principal Identity\n              using which the CRUD operations should be performed\n            - Must be specified if nsx_cert_path is specified\n        type: str\n    request_headers:\n        description: HTTP request headers to be sent to the host while making\n                     any request\n        type: dict\n    add_tags:\n        type: list\n        element: dict\n        description: List of tags to be applied to the virtual machine\n        suboptions:\n            scope:\n                description: Tag scope.\n                default: \"\"\n                type: str\n            tag:\n                description: Tag value.\n                default: \"\"\n                type: str\n    remove_tags_with_scope:\n        type: list\n        element: str\n        description:\n            - Specify the scope of the tags that should be removed\n            - If remove_other_tags is True, this becomes do not care\n    virtual_machine_id:\n        description: The identifier that is used in the enforcement point that\n                     uniquely identifies the virtual machine. In case of NSXT\n                     it would be the value of the external_id of the virtual\n                     machine.\n        type: str\n    virtual_machine_display_name:\n        description: Display name of the VM whose tags are to be updated.\n                     Either this or virtual_machine_id must be specified. If\n                     both are specified, virtual_machine_id is used\n        type: str\n    remove_other_tags:\n        description:\n            - Remove the tags that are not specified in the add_tags\n            - Caution; If this is True, all tags that are not in add_tags will\n              be removed\n        default: false\n'''\n\nEXAMPLES = '''\n- name: Update Tags on VMs\n  nsxt_vm_tags:\n    hostname: \"10.10.10.10\"\n    nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n    nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n    validate_certs: False\n    virtual_machine_display_name: App-VM-1\n    remove_other_tags: False\n    add_tags:\n      - scope: my-scope\n        tag: my-tag\n    remove_tags_with_scope:\n      - my-scope1\n'''\n\nRETURN = '''# '''\n\n\nfrom ansible.module_utils.basic import AnsibleModule\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.policy_communicator import PolicyCommunicator\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_resource_urls import VM_LIST_URL, VM_UPDATE_URL\nfrom ansible.module_utils._text import to_native\n\n\ndef get_resource_spec():\n    vm_tag_spec = PolicyCommunicator.get_vmware_argument_spec()\n    vm_tag_spec.update(dict(\n        virtual_machine_id=dict(type='str'),\n        virtual_machine_display_name=dict(type='str'),\n        add_tags=dict(type='list', elements='dict', default=[],\n                      options=dict(\n                          scope=dict(required=False, type='str', default=\"\"),\n                          tag=dict(required=False, type='str', default=\"\"))),\n        remove_other_tags=dict(\n            required=False, default=False, type='bool')),\n        remove_tags_with_scope=dict(type='list', elements='str', default=[]))\n    return vm_tag_spec\n\n\nclass TagElement(object):\n    def __init__(self, tag):\n        self.scope, self.tag = tag['scope'], tag.get('tag')\n        self.element = (self.scope, self.tag)\n\n    def __eq__(self, other):\n        if self.tag is None:\n            return self.scope == other.scope\n        return self.element == other.element\n\n    def __hash__(self):\n        return hash(self.element)\n\ndef _fetch_all_tags_on_vm_and_infer_id(\n        vm_id, policy_communicator, vm_display_name, module):\n    target_vm = None\n    if vm_id:\n        _, vms = policy_communicator.request(VM_LIST_URL+'?external_id='+vm_id, base_url='fabric')\n        if vms['result_count'] == 0:\n            module.fail_json(msg=\"No VM found with the provided \"\n                    \"virtual_machine_id\")\n        elif vms['result_count'] == 1:\n            return vms['results'][0].get('tags', []), vm_id\n        else:\n            # Multiple VMs with same external id name.\n            # This should not happen.\n            module.fail_json(msg=\"Multiple VMs with same external \"\n                    \"id. Please investigate the environment.\")\n    else:\n        _, vms = policy_communicator.request(VM_LIST_URL+'?display_name='+vm_display_name, base_url='fabric')\n        if vms['result_count'] == 0:\n            module.fail_json(msg=\"No VM found with the provided \"\n                    \"virtual_machine_display_name\")\n        elif vms['result_count'] == 1:\n            return vms['results'][0].get('tags', []), vms['results'][0]['external_id']\n        else:\n            # Multiple VMs with same display name. Ask user\n            # to provide VM ID instead\n            module.fail_json(msg=\"Multiple VMs with same display \"\n                    \"name. Please provide \"\n                    \"virtual_machine_id to identify the \"\n                    \"target VM\")\n\n\ndef _get_tags_as_set(tags=[], scope_list=[]):\n    tag_set = set()\n    if tags:\n        for tag in tags:\n            if tag['scope'] is None:\n                tag['scope'] = ''\n            tag_set.add(TagElement(tag))\n    if scope_list:\n        for scope in scope_list:\n            tag_set.add(TagElement({'scope': scope, 'tag': \"\"}))\n    return tag_set\n\n\ndef _read_tags_from_module_params(module_params, tag_identifier):\n    return module_params[tag_identifier] or []\n\n\ndef realize():\n    module = AnsibleModule(\n        argument_spec=get_resource_spec(),\n        supports_check_mode=False)\n\n    virtual_machine_id = module.params['virtual_machine_id']\n    virtual_machine_display_name = None\n    if not virtual_machine_id:\n        virtual_machine_display_name = module.params[\n            'virtual_machine_display_name']\n        if not virtual_machine_display_name:\n            module.fail_json(msg=\"Please specify either virtual_machine_id or \"\n                                 \"virtual_machine_display_name in the \"\n                                 \"playbook\")\n\n    mgr_hostname = module.params.pop('hostname')\n    mgr_username = module.params.pop('username')\n    mgr_password = module.params.pop('password')\n\n    nsx_cert_path = module.params['nsx_cert_path']\n    nsx_key_path = module.params['nsx_key_path']\n\n    request_headers = module.params['request_headers']\n    ca_path = module.params['ca_path']\n\n    validate_certs = module.params.pop('validate_certs')\n\n    try:\n        # Each manager has an associated PolicyCommunicator\n        policy_communicator = PolicyCommunicator.get_instance(\n            mgr_hostname, mgr_username, mgr_password, nsx_cert_path,\n            nsx_key_path, request_headers, ca_path, validate_certs)\n\n        all_tags, virtual_machine_id = _fetch_all_tags_on_vm_and_infer_id(\n            virtual_machine_id, policy_communicator,\n            virtual_machine_display_name, module)\n        init_tags_set = _get_tags_as_set(tags=all_tags)\n        if module.params.get('remove_other_tags'):\n            tags_to_add = _get_tags_as_set(tags=_read_tags_from_module_params(\n                module.params, 'add_tags'))\n            for i, tag in enumerate(all_tags):\n                if TagElement(tag) not in tags_to_add:\n                    all_tags[i] = None\n        elif _read_tags_from_module_params(\n                module.params, 'remove_tags_with_scope'):\n            tags_to_remove = _get_tags_as_set(\n                scope_list=_read_tags_from_module_params(\n                    module.params, 'remove_tags_with_scope'))\n            for i, tag in enumerate(all_tags):\n                if TagElement(tag) in tags_to_remove:\n                    all_tags[i] = None\n\n        final_tags = [tag for tag in all_tags if tag is not None]\n        final_tags_set = _get_tags_as_set(tags=final_tags)\n        for tag in _read_tags_from_module_params(module.params, 'add_tags'):\n            tag_element = TagElement(tag)\n            if tag_element not in final_tags_set:\n                final_tags += tag,\n                final_tags_set.add(tag_element)\n\n        if init_tags_set == final_tags_set:\n            module.exit_json(msg=\"No tags detected to update\")\n\n        post_body = {\n            \"external_id\": virtual_machine_id,\n            \"tags\": final_tags\n        }\n        policy_communicator.request(\n            VM_UPDATE_URL + '?action=update_tags', data=post_body,\n            method=\"POST\", base_url='fabric')\n        module.exit_json(msg=\"Successfully updated tags on VM {}\".format(\n            virtual_machine_id), changed=True)\n    except Exception as err:\n        module.fail_json(msg=\"Failed to update tags on VM {} as API \"\n                         \"returned error: {}. Please try \"\n                         \"again\".format(virtual_machine_id, err))\n\n\nif __name__ == '__main__':\n    realize()\n"
  },
  {
    "path": "tests/playbooks/mp/answerfile.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\nhostname: \"10.192.254.207\"\nusername: \"admin\"\npassword: \"Admin!23Admin\"\nvalidate_certs: False\n\nip_pools:\n- display_name: IPPool-IPV4-1\n  subnets:\n  - allocation_ranges:\n    - start: \"10.112.201.28\"\n      end: \"10.112.201.35\"\n    cidr: \"10.112.201.0/24\"\n\ntransportzones:\n- display_name: \"TZ1\"\n  tz_type: \"VLAN_BACKED\"\n# - display_name: \"TZ2\"\n#   tz_type: \"OVERLAY_BACKED\"\n\nuplink_profiles:\n- display_name: uplinkProfile1\n  teaming:\n    active_list:\n    - uplink_name: \"uplink-1\"\n      uplink_type: PNIC\n    policy: FAILOVER_ORDER\n  transport_vlan: 0\n# - display_name: uplinkProfile2\n#   teaming:\n#     active_list:\n#     - uplink_name: \"uplink-2\"\n#       uplink_type: PNIC\n#     policy: FAILOVER_ORDER\n#   transport_vlan: 0\n\nhost_transport_nodes:\n- display_name: TN1\n  host_switches:\n  - host_switch_profiles:\n    - name: uplinkProfile1\n      type: UplinkHostSwitchProfile\n    host_switch_name: hostswitch1\n    host_switch_mode: STANDARD\n    pnics:\n    - device_name: \"vmnic1\"\n      uplink_name: \"uplink-1\"\n    ip_assignment_spec:\n      resource_type: StaticIpPoolSpec\n      ip_pool_name: \"IPPool-IPV4-1\"\n    transport_zone_endpoints:\n    - transport_zone_name: \"TZ1\"\n  transport_zone_endpoints:\n  - transport_zone_name: \"TZ1\"\n  node_deployment_info:\n    resource_type: \"HostNode\"\n    display_name: \"Host_1\"\n    ip_addresses: [\"10.161.136.35\"]\n    os_type: \"ESXI\"\n    os_version: \"6.5.0\"\n    host_credential:\n      username: \"root\"\n      password: \"ca$hc0w\"\n\nedge_transport_nodes:\n- display_name: EdgeTN1\n  host_switches:\n  - host_switch_profiles:\n    - name: nsx-edge-single-nic-uplink-profile\n      type: UplinkHostSwitchProfile\n    host_switch_name: nsxHostSwitch\n    host_switch_mode: STANDARD\n    pnics:\n    - device_name: \"fp-eth0\"\n      uplink_name: \"uplink-1\"\n    ip_assignment_spec:\n      resource_type: StaticIpListSpec\n      ip_list: [\"192.168.32.1\"]\n      subnet_mask: \"255.255.255.254\"\n      default_gateway: \"192.168.32.0\"\n    transport_zone_endpoints:\n    - transport_zone_name: \"nsx-overlay-transportzone\"\n  node_deployment_info:\n    resource_type: \"EdgeNode\"\n    display_name: \"EdgeTN1\"\n    deployment_type: \"VIRTUAL_MACHINE\"\n    deployment_config:\n      form_factor: \"SMALL\"\n      node_user_settings:\n        cli_username: \"admin\"\n        cli_password: \"Admin!23Admin\"\n        root_password: \"Admin!23Admin\"\n      vm_deployment_config:\n        ipv4_assignment_enabled: false\n        ipv6_assignment_type: \"STATIC\"\n        management_port_subnets:\n          - ip_addresses:\n              - \"2002:0:0:0:0:0:0:10\"\n            prefix_length: 64\n        default_gateway_addresses:\n          - \"2002:0:0:0:0:0:0:10\"\n        placement_type: VsphereDeploymentConfig\n        vc_name: \"VC\"\n        vc_username: \"administrator@vsphere.local\"\n        vc_password:  \"VMware$123\"\n        data_networks:\n        - VM Network\n        - VM Network\n        - VM Network\n        management_network: \"VM Network\"\n        compute: \"HostCluster1\"\n        storage: \"datastore-esx67-4\"\n        host: \"10.105.15.236\"\n    node_settings:\n      allow_ssh_root_login: true\n      enable_ssh: true\n      hostname: \"edge.vmware.com\"\n      \ntransport_node_profiles:\n- display_name: TNP1\n  host_switches:\n  - host_switch_profiles:\n    - name: uplinkProfile1\n      type: UplinkHostSwitchProfile\n    host_switch_name: hostswitch1\n    host_switch_mode: STANDARD\n    pnics:\n    - device_name: vmnic1\n      uplink_name: \"uplink-1\"\n    ip_assignment_spec:\n      resource_type: StaticIpPoolSpec\n      ip_pool_name: \"IPPool-IPV4-1\"\n    transport_zone_endpoints:\n    - transport_zone_name: \"TZ1\"\n\n\ncompute_managers:\n- display_name: \"VC1\"\n  server: \"10.161.129.87\"\n  origin_type: vCenter\n  credential_type: UsernamePasswordLoginCredential\n  username: \"administrator@vsphere.local\"\n  password: \"Admin!23\"\n  thumbprint: \"46:1E:31:DD:0B:37:4C:F0:91:5B:49:A1:A1:94:B5:DF:82:93:90:52:D9:68:0F:86:C8:CA:6C:34:CB:82:D7:D5\"\n\n\nroute_advertise:\n  display_name: \"tier-1\" # Must be a tier 1 router name\n  enabled: True\n  advertise_dns_forwarder: False\n  advertise_lb_snat_ip: True\n  advertise_lb_vip: True\n  advertise_nat_routes: True\n  advertise_nsx_connected_routes: True\n  advertise_static_routes: True\n\n\n#\n# vIDM properties\n#\nvidm:\n  client_id: \"NSX_client_credentials_client_ID\"\n  client_secret: \"NSX_client_credentials_client_SECRET\"\n  host_name: \"colo-vshield3-dhcp168.eng.vmware.com\"\n  lb_enable: False\n  node_host_name: \"10.186.17.88\"\n  thumbprint: \"BF838E7A1CF7B84F7B556F35E0D9A0A365F6AE021885809A2D42AAF78A06B0A4\"\n\n\n#\n# One or more local managers that have to be registered with NSX\n#\nlocal_managers:\n- display_name: \"My LM1\"\n  id: \"LM1\"\n  fqdn: \"10.186.3.163\"\n  username: \"admin\"\n  password: \"Admin!23Admin\"\n  thumbprint: \"ec8ba0322b987bc7bce14097667104f43340befce84d75e0820b02a2f3839441\"\n- id: \"LM2\"\n  display_name: \"\"\n  fqdn: \"10.182.6.97\"\n  username: \"admin\"\n  password: \"Admin!23Admin\"\n  thumbprint: \"d2ec50124fcd487c37d46f85d8f6f80b24441f4e5ed9cac5c8c47d2649043078\"\n\n\n\n#\n# One or more global managers that have to be registered with current global manager\n#\nglobal_managers:\n- display_name: \"10.92.78.184\"\n  fqdn: \"10.92.78.184\"\n  username: \"admin\"\n  password: \"Admin!23Admin\"\n  thumbprint: \"703e69dce489beaa1a683d12a16efbf9c81630d23c5f32fc25becc5340169f1e\"\n  mode: \"STANDBY\"\n"
  },
  {
    "path": "tests/playbooks/mp/answerfile_9x.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\nhostname: \"10.192.254.207\"\nusername: \"admin\"\npassword: \"Admin!23Admin\"\nvalidate_certs: False\n\nip_pools:\n- display_name: IPPool-IPV4-1\n  pool_static_subnets:\n  - display_name: test-ip-static-subnet-1\n    state: present\n    allocation_ranges:\n    - start: \"10.112.201.28\"\n      end: \"10.112.201.35\"\n    cidr: \"10.112.201.0/24\"\n\ntransportzones:\n- display_name: \"TZ1\"\n  tz_type: \"VLAN_BACKED\"\n# - display_name: \"TZ2\"\n#   tz_type: \"OVERLAY_BACKED\"\n\nuplink_profiles:\n- display_name: uplinkProfile1\n  teaming:\n    active_list:\n    - uplink_name: \"uplink-1\"\n      uplink_type: PNIC\n    policy: FAILOVER_ORDER\n  transport_vlan: 0\n# - display_name: uplinkProfile2\n#   teaming:\n#     active_list:\n#     - uplink_name: \"uplink-2\"\n#       uplink_type: PNIC\n#     policy: FAILOVER_ORDER\n#   transport_vlan: 0\n\nhost_transport_nodes:\n- display_name: TN1\n  resource_type: \"HostTransportNode\"\n  host_switches:\n  - host_switch_profiles:\n    - name: uplinkProfile1\n      type: UplinkHostSwitchProfile\n    host_switch_name: hostswitch1\n    host_switch_mode: ENS_INTERRUPT\n#    host_switch_mode: STANDARD\n    host_switch_type: VDS\n    uplinks:\n    - vds_uplink_name: Uplink 1\n      uplink_name: uplink-1\n    ip_assignment_spec:\n      resource_type: StaticIpPoolSpec\n      ip_pool_name: \"IPPool-IPV4-1\"\n    transport_zone_endpoints:\n    - transport_zone_name: \"TZ1\"\n  node_deployment_info:\n    resource_type: \"HostNode\"\n    display_name: \"Host_1\"\n    ip_addresses: [\"10.161.136.35\"]\n    os_type: \"ESXI\"\n    os_version: \"9.0.0\"\n    host_credential:\n      username: \"root\"\n      password: \"ca$hc0w\"\n\nedge_transport_nodes:\n- display_name: EdgeTN1\n  host_switches:\n  - host_switch_profiles:\n    - name: nsx-edge-single-nic-uplink-profile\n      type: UplinkHostSwitchProfile\n    host_switch_name: nsxHostSwitch\n    host_switch_mode: STANDARD\n    pnics:\n    - device_name: \"fp-eth0\"\n      uplink_name: \"uplink-1\"\n    ip_assignment_spec:\n      resource_type: StaticIpListSpec\n      ip_list: [\"192.168.32.1\"]\n      subnet_mask: \"255.255.255.254\"\n      default_gateway: \"192.168.32.0\"\n    transport_zone_endpoints:\n    - transport_zone_name: \"nsx-overlay-transportzone\"\n  node_deployment_info:\n    resource_type: \"EdgeNode\"\n    display_name: \"EdgeTN1\"\n    deployment_type: \"VIRTUAL_MACHINE\"\n    deployment_config:\n      form_factor: \"SMALL\"\n      node_user_settings:\n        cli_username: \"admin\"\n        cli_password: \"Admin!23Admin\"\n        root_password: \"Admin!23Admin\"\n      vm_deployment_config:\n        ipv4_assignment_enabled: false\n        ipv6_assignment_type: \"STATIC\"\n        management_port_subnets:\n          - ip_addresses:\n              - \"2002:0:0:0:0:0:0:10\"\n            prefix_length: 64\n        default_gateway_addresses:\n          - \"2002:0:0:0:0:0:0:10\"\n        placement_type: VsphereDeploymentConfig\n        vc_name: \"VC\"\n        vc_username: \"administrator@vsphere.local\"\n        vc_password:  \"VMware$123\"\n        data_networks:\n        - VM Network\n        - VM Network\n        - VM Network\n        management_network: \"VM Network\"\n        compute: \"HostCluster1\"\n        storage: \"datastore-esx67-4\"\n        host: \"10.105.15.236\"\n    node_settings:\n      allow_ssh_root_login: true\n      enable_ssh: true\n      hostname: \"edge.vmware.com\"\n\ntransport_node_profiles:\n- display_name: TNP1\n  host_switches:\n  - host_switch_profiles:\n    - name: uplinkProfile1\n      type: UplinkHostSwitchProfile\n#    host_switch_name: hostswitch1\n    host_switch_id: \"50 17 4c 3f 86 bf 44 be-11 6f 69 80 90 f7 22 21\"\n    host_switch_mode: STANDARD\n    host_switch_type: VDS\n    uplinks:\n    - vds_uplink_name: Uplink 1\n      uplink_name: uplink-1\n    ip_assignment_spec:\n      resource_type: StaticIpPoolSpec\n      ip_pool_name: \"IPPool-IPV4-1\"\n    transport_zone_endpoints:\n    - transport_zone_name: \"TZ1\"\n\n\ncompute_managers:\n- display_name: \"VC1\"\n  server: \"10.161.129.87\"\n  origin_type: vCenter\n  credential_type: UsernamePasswordLoginCredential\n  username: \"administrator@vsphere.local\"\n  password: \"Admin!23\"\n  thumbprint: \"46:1E:31:DD:0B:37:4C:F0:91:5B:49:A1:A1:94:B5:DF:82:93:90:52:D9:68:0F:86:C8:CA:6C:34:CB:82:D7:D5\"\n\n\nroute_advertise:\n  display_name: \"tier-1\" # Must be a tier 1 router name\n  enabled: True\n  advertise_dns_forwarder: False\n  advertise_lb_snat_ip: True\n  advertise_lb_vip: True\n  advertise_nat_routes: True\n  advertise_nsx_connected_routes: True\n  advertise_static_routes: True\n\n\n#\n# vIDM properties\n#\nvidm:\n  client_id: \"NSX_client_credentials_client_ID\"\n  client_secret: \"NSX_client_credentials_client_SECRET\"\n  host_name: \"colo-vshield3-dhcp168.eng.vmware.com\"\n  lb_enable: False\n  node_host_name: \"10.186.17.88\"\n  thumbprint: \"BF838E7A1CF7B84F7B556F35E0D9A0A365F6AE021885809A2D42AAF78A06B0A4\"\n\n\n#\n# One or more local managers that have to be registered with NSX\n#\nlocal_managers:\n- display_name: \"My LM1\"\n  id: \"LM1\"\n  fqdn: \"10.186.3.163\"\n  username: \"admin\"\n  password: \"Admin!23Admin\"\n  thumbprint: \"ec8ba0322b987bc7bce14097667104f43340befce84d75e0820b02a2f3839441\"\n- id: \"LM2\"\n  display_name: \"\"\n  fqdn: \"10.182.6.97\"\n  username: \"admin\"\n  password: \"Admin!23Admin\"\n  thumbprint: \"d2ec50124fcd487c37d46f85d8f6f80b24441f4e5ed9cac5c8c47d2649043078\"\n\n\n\n#\n# One or more global managers that have to be registered with current global manager\n#\nglobal_managers:\n- display_name: \"10.92.78.184\"\n  fqdn: \"10.92.78.184\"\n  username: \"admin\"\n  password: \"Admin!23Admin\"\n  thumbprint: \"703e69dce489beaa1a683d12a16efbf9c81630d23c5f32fc25becc5340169f1e\"\n  mode: \"STANDBY\"\n"
  },
  {
    "path": "tests/playbooks/mp/answerfile_attach_tnp_to_cluster.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\nhostname: \"10.161.157.200\"\nusername: \"admin\"\npassword: \"Admin!23Admin\"\nvalidate_certs: False\n\nip_pools:\n- display_name: IPPool-IPV4-1\n  subnets:\n  - allocation_ranges:\n    - start: \"10.112.201.28\"\n      end: \"10.112.201.35\"\n    cidr: \"10.112.201.0/24\"\n\ntransportzones:\n- display_name: \"TZ1\"\n  transport_type: \"OVERLAY\"\n  host_switch_name: \"hostswitch1\"\n\nuplink_profiles:\n- display_name: uplinkProfile1\n  teaming:\n    active_list:\n    - uplink_name: \"uplink-1\"\n      uplink_type: PNIC\n    policy: FAILOVER_ORDER\n  transport_vlan: 0\n\ntransport_node_profiles:\n- display_name: TNP1\n  host_switches:\n  - host_switch_profiles:\n    - name: uplinkProfile1\n      type: UplinkHostSwitchProfile\n    host_switch_name: hostswitch1\n    pnics:\n    - device_name: vmnic1\n      uplink_name: \"uplink-1\"\n    ip_assignment_spec:\n      resource_type: StaticIpPoolSpec\n      ip_pool_name: \"IPPool-IPV4-1\"\n  transport_zone_endpoints:\n  - transport_zone_name: \"TZ1\"\n\n\ncompute_managers:\n- display_name: \"VC1\"\n  server: \"10.161.129.87\"\n  origin_type: vCenter\n  credential_type: UsernamePasswordLoginCredential\n  username: \"administrator@vsphere.local\"\n  password: \"Admin!23\"\n  thumbprint: \"46:1E:31:DD:0B:37:4C:F0:91:5B:49:A1:A1:94:B5:DF:82:93:90:52:D9:68:0F:86:C8:CA:6C:34:CB:82:D7:D5\"\n"
  },
  {
    "path": "tests/playbooks/mp/answerfile_attach_tnp_to_cluster_9x.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\nhostname: \"10.161.157.200\"\nusername: \"admin\"\npassword: \"Admin!23Admin\"\nvalidate_certs: False\n\nip_pools:\n- display_name: IPPool-IPV4-1\n  pool_static_subnets:\n  - display_name: test-ip-static-subnet-1\n    state: present\n    allocation_ranges:\n    - start: \"10.112.201.28\"\n      end: \"10.112.201.35\"\n    cidr: \"10.112.201.0/24\"\n\ntransportzones:\n- display_name: \"TZ1\"\n  tz_type: \"OVERLAY_BACKED\"\n\nuplink_profiles:\n- display_name: uplinkProfile1\n  teaming:\n    active_list:\n    - uplink_name: \"uplink-1\"\n      uplink_type: PNIC\n    policy: FAILOVER_ORDER\n  transport_vlan: 0\n\ntransport_node_profiles:\n- display_name: TNP1\n  host_switches:\n  - host_switch_profiles:\n    - name: uplinkProfile1\n      type: UplinkHostSwitchProfile\n    host_switch_name: hostswitch1\n    host_switch_type: VDS\n    uplinks:\n    - vds_uplink_name: Uplink 1\n      uplink_name: uplink-1\n    ip_assignment_spec:\n      resource_type: StaticIpPoolSpec\n      ip_pool_name: \"IPPool-IPV4-1\"\n    transport_zone_endpoints:\n    - transport_zone_name: \"TZ1\"\n\n\ncompute_managers:\n- display_name: \"VC1\"\n  server: \"10.161.129.87\"\n  origin_type: vCenter\n  credential_type: UsernamePasswordLoginCredential\n  username: \"administrator@vsphere.local\"\n  password: \"Admin!23\"\n  thumbprint: \"46:1E:31:DD:0B:37:4C:F0:91:5B:49:A1:A1:94:B5:DF:82:93:90:52:D9:68:0F:86:C8:CA:6C:34:CB:82:D7:D5\"\n"
  },
  {
    "path": "tests/playbooks/mp/answerfile_tn.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\nhostname: \"10.161.157.200\"\nusername: \"admin\"\npassword: \"Admin!23Admin\"\nvalidate_certs: False\n\nip_pools:\n- display_name: IPPool-IPV4-1\n  subnets:\n  - allocation_ranges:\n    - start: \"10.112.201.28\"\n      end: \"10.112.201.35\"\n    cidr: \"10.112.201.0/24\"\n\ntransportzones:\n- display_name: \"TZ1\"\n  transport_type: \"OVERLAY\"\n  host_switch_name: \"hostswitch1\"\n\nuplink_profiles:\n- display_name: uplinkProfile1\n  teaming:\n    active_list:\n    - uplink_name: \"uplink-1\"\n      uplink_type: PNIC\n    policy: FAILOVER_ORDER\n  transport_vlan: 0\n\ntransport_nodes:\n- display_name: TN1\n  host_switches:\n  - host_switch_profiles:\n    - name: uplinkProfile1\n      type: UplinkHostSwitchProfile\n    host_switch_name: hostswitch1\n    # pnics:\n    # - device_name: \"vmnic1\"\n    #   uplink_name: \"uplink-1\"\n    ip_assignment_spec:\n      resource_type: StaticIpPoolSpec\n      ip_pool_name: \"IPPool-IPV4-1\"\n  transport_zone_endpoints:\n  - transport_zone_name: \"TZ1\"\n  node_deployment_info:\n    # Host node deployment info ESXI\n    # resource_type: \"HostNode\"\n    # display_name: \"Host_1\"\n    # ip_addresses: [\"10.161.136.35\"]\n    # os_type: \"ESXI\"\n    # os_version: \"6.5.0\"\n    # host_credential:\n    #   username: \"root\"\n    #   password: \"ca$hc0w\"\n    #   thumbprint: \"aba87c8b3a042435e0f3d60784c1fbc6f1aba5ce71f6efb2601fd26fb5453bb0\"\n    resource_type: \"HostNode\"\n    display_name: \"Host_3\"\n    ip_addresses: [\"10.192.44.93\"]\n    os_type: \"UBUNTUKVM\"\n    os_version: \"16.04\"\n    host_credential:\n      username: \"root\"\n      password: \"ca$hc0w\"\n      thumbprint: \"3fS+Ik4O0GOMuQ8Chbxfn7KBLjmLhhnEHPKDXnt/AFQ=\"\n"
  },
  {
    "path": "tests/playbooks/mp/answerfile_tn_9x.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\nhostname: \"10.161.157.200\"\nusername: \"admin\"\npassword: \"Admin!23Admin\"\nvalidate_certs: False\n\nip_pools:\n- display_name: IPPool-IPV4-1\n  pool_static_subnets:\n  - display_name: test-ip-static-subnet-1\n    state: present\n    allocation_ranges:\n    - start: \"10.112.201.28\"\n      end: \"10.112.201.35\"\n    cidr: \"10.112.201.0/24\"\n\ntransportzones:\n- display_name: \"TZ1\"\n  tz_type: \"OVERLAY_BACKED\"\n\nuplink_profiles:\n- display_name: uplinkProfile1\n  teaming:\n    active_list:\n    - uplink_name: \"uplink-1\"\n      uplink_type: PNIC\n    policy: FAILOVER_ORDER\n  transport_vlan: 0\n\ntransport_nodes:\n- display_name: TN1\n  host_switches:\n  - host_switch_profiles:\n    - name: uplinkProfile1\n      type: UplinkHostSwitchProfile\n    host_switch_name: hostswitch1\n    host_switch_type: VDS\n    host_switch_mode: ENS_INTERRUPT\n    uplinks:\n      - vds_uplink_name: Uplink 1\n        uplink_name: uplink-1\n    ip_assignment_spec:\n      resource_type: StaticIpPoolSpec\n      ip_pool_name: \"IPPool-IPV4-1\"\n    transport_zone_endpoints:\n    - transport_zone_name: \"TZ1\"\n  node_deployment_info:\n    # Host node deployment info ESXI\n     resource_type: \"HostNode\"\n     display_name: \"Host_1\"\n     ip_addresses: [\"10.161.96.247\"]\n     os_type: \"ESXI\"\n     os_version: \"9.0.0\"\n     host_credential:\n       username: \"root\"\n       password: \"ca$hc0w\"\n       thumbprint: \"85:03:6A:33:CA:AF:EE:24:67:C0:02:F5:B0:77:AE:DD:FC:31:19:93:44:77:76:C9:E6:4B:61:4D:9A:9E:72:98\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_attach_tnp_to_cluster.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile_attach_tnp_to_cluster.yml\n  tasks:\n    - name: Register compute manager\n      vmware.ansible_for_nsxt.nsxt_fabric_compute_managers:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: False\n          display_name: \"{{item.display_name}}\"\n          server: \"{{item.server}}\"\n          origin_type: \"{{item.origin_type}}\"\n          credential:\n            credential_type: \"{{item.credential_type}}\"\n            username: \"{{item.username}}\"\n            password: \"{{item.password}}\"\n            thumbprint: \"{{item.thumbprint}}\"\n          state: present\n      with_items:\n        - \"{{compute_managers}}\"\n\n    - name: Create ip pool\n      vmware.ansible_for_nsxt.nsxt_ip_pools:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        subnets: \"{{item.subnets}}\"\n        state: present\n      with_items:\n        - \"{{ip_pools}}\"\n\n    - name: Create transport zone\n      vmware.ansible_for_nsxt.nsxt_transport_zones:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: \"TransportZone\"\n        display_name: \"{{item.display_name}}\"\n        description: \"NSX configured Test Transport Zone\"\n        transport_type: \"{{item.transport_type}}\"\n        host_switch_name: \"{{item.host_switch_name}}\"\n        state: \"present\"\n      with_items:\n        - \"{{transportzones}}\"\n\n    - name: Create uplink profile\n      vmware.ansible_for_nsxt.nsxt_uplink_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: UplinkHostSwitchProfile\n        display_name: \"{{item.display_name}}\"\n        mtu: 1600\n        teaming: \"{{item.teaming}}\"\n        transport_vlan: \"{{item.transport_vlan}}\"\n        state: \"present\"\n      with_items:\n        - \"{{uplink_profiles}}\"\n\n    - name: Create transport node profile\n      vmware.ansible_for_nsxt.nsxt_transport_node_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: TransportNodeProfile\n        display_name: \"{{item.display_name}}\"\n        description: NSX configured Test Transport Node Profile\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        transport_zone_endpoints: \"{{item.transport_zone_endpoints}}\"\n        state: present\n      with_items:\n        - \"{{transport_node_profiles}}\"\n\n    - name: Attach Transport node profile to cluster\n      vmware.ansible_for_nsxt.nsxt_transport_node_collections:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"TNC1\"\n        resource_type: \"TransportNodeCollection\"\n        description: \"Transport Node Collections 1\"\n        compute_manager_name: \"VC1\"\n        cluster_name: \"os-compute-cluster-1\"\n        transport_node_profile_name: \"TNP1\"\n        state: present\n"
  },
  {
    "path": "tests/playbooks/mp/test_attach_tnp_to_cluster_9x.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile_attach_tnp_to_cluster_9x.yml\n  tasks:\n    - name: Register compute manager\n      vmware.ansible_for_nsxt.nsxt_fabric_compute_managers:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: False\n          display_name: \"{{item.display_name}}\"\n          server: \"{{item.server}}\"\n          origin_type: \"{{item.origin_type}}\"\n          credential:\n            credential_type: \"{{item.credential_type}}\"\n            username: \"{{item.username}}\"\n            password: \"{{item.password}}\"\n            thumbprint: \"{{item.thumbprint}}\"\n          state: present\n      with_items:\n        - \"{{compute_managers}}\"\n\n    - name: Create ip pool\n      vmware.ansible_for_nsxt.nsxt_policy_ip_pool:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        pool_static_subnets: \"{{item.pool_static_subnets}}\"\n        state: present\n      with_items:\n        - \"{{ip_pools}}\"\n\n    - name: Create transport zone\n      vmware.ansible_for_nsxt.nsxt_transport_zones:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: \"PolicyTransportZone\"\n        display_name: \"{{item.display_name}}\"\n        description: \"NSX configured Test Transport Zone\"\n        tz_type: \"{{item.tz_type}}\"\n        state: \"present\"\n      with_items:\n        - \"{{transportzones}}\"\n\n    - name: Create uplink profile\n      vmware.ansible_for_nsxt.nsxt_uplink_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: UplinkHostSwitchProfile\n        display_name: \"{{item.display_name}}\"\n        teaming: \"{{item.teaming}}\"\n        transport_vlan: \"{{item.transport_vlan}}\"\n        state: \"present\"\n      with_items:\n        - \"{{uplink_profiles}}\"\n\n    - name: Create transport node profile\n      vmware.ansible_for_nsxt.nsxt_transport_node_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: PolicyHostTransportNodeProfile\n        display_name: \"{{item.display_name}}\"\n        description: NSX configured Test Transport Node Profile\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        state: present\n      with_items:\n        - \"{{transport_node_profiles}}\"\n\n    - name: Attach Transport node profile to cluster\n      vmware.ansible_for_nsxt.nsxt_transport_node_collections:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"TNC1\"\n        resource_type: \"TransportNodeCollection\"\n        description: \"Transport Node Collections 1\"\n        compute_manager_name: \"VC1\"\n        cluster_name: \"os-compute-cluster-1\"\n        transport_node_profile_name: \"TNP1\"\n        state: present\n"
  },
  {
    "path": "tests/playbooks/mp/test_basic_topology.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: deploy NSX Manager OVA\n      vmware.ansible_for_nsxt.nsxt_deploy_ova:\n        ovftool_path: \"/usr/bin\"\n        datacenter: \"private_dc\"\n        datastore: \"data store\"\n        portgroup: \"VM Network\"\n        cluster: \"nsxt_cluster\"\n        vmname: \"nsxt-manager\"\n        hostname: \"nsxt-manager-10\"\n        dns_server: \"20.162.244.213\"\n        dns_domain: \"eng.vmware.com\"\n        ntp_server: \"123.110.200.124\"\n        gateway: \"10.112.203.253\"\n        ip_address: \"40.112.201.24\"\n        netmask: \"255.255.224.0\"\n        admin_password: \"Admin!23Admin\"\n        cli_password: \"Admin!23Admin\"\n        path_to_ova: \"http://build-squid.eng.vmware.com/build/mts/release/bora-8411846/publish/nsx-unified-appliance/exports/ovf\"\n        ova_file: \"nsx-unified-appliance-2.2.0.0.0.8411854.ovf\"\n        vcenter: \"10.161.244.213\"\n        vcenter_user: \"administrator@vsphere.local\"\n        vcenter_passwd: \"Admin!23\"\n        deployment_size: \"small\"\n        role: \"nsx-manager nsx-controller\"\n\n    - name: Check manager status\n      vmware.ansible_for_nsxt.nsxt_manager_status:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: False\n          wait_time: 50\n\n    - name: Deploy compute manager\n      vmware.ansible_for_nsxt.nsxt_fabric_compute_managers:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: False\n          display_name: \"vCenter\"\n          server: \"10.161.244.213\"\n          origin_type: vCenter\n          credential:\n            credential_type: UsernamePasswordLoginCredential\n            username: \"administrator@vsphere.local\"\n            password: \"Admin!23\"\n            thumbprint: \"36:43:34:D9:C2:06:27:4B:EE:C3:4A:AE:23:BF:76:A0:0C:4D:D6:8A:D3:16:55:97:62:07:C2:84:0C:D8:BA:66\"\n          state: present\n      register: compute_manager\n\n    - name: Deploy controller\n      vmware.ansible_for_nsxt.nsxt_controllers:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: False\n          deployment_requests:\n          - roles:\n            - CONTROLLER\n            form_factor: \"MEDIUM\"\n            user_settings:\n              cli_password: \"Admin!23Admin\"\n              root_password: \"Admin!23Admin\"\n            deployment_config:\n              placement_type: VsphereClusterNodeVMDeploymentConfig\n              vc_id: \"{{compute_manager.id}}\"\n              management_network_id: \"network-44\"\n              hostname: \"controller-1\"\n              compute_id: \"domain-c49\"\n              storage_id: \"datastore-43\"\n              default_gateway_addresses:\n              - 11.122.203.253\n              management_port_subnets:\n              - ip_addresses:\n                - 11.142.201.25\n                prefix_length: \"19\"\n          clustering_config:\n            clustering_type: ControlClusteringConfig\n            shared_secret: \"123456\"\n            join_to_existing_cluster: false\n          state: present\n\n    - name: Create ip pool\n      vmware.ansible_for_nsxt.nsxt_ip_pools:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        subnets: \"{{item.subnets}}\"\n        state: present\n      with_items:\n        - \"{{ip_pools}}\"\n\n    - name: Create transport zone\n      vmware.ansible_for_nsxt.nsxt_transport_zones:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: \"TransportZone\"\n        display_name: \"{{item.display_name}}\"\n        description: \"NSX configured Test Transport Zone\"\n        transport_type: \"{{item.transport_type}}\"\n        host_switch_name: \"{{item.host_switch_name}}\"\n        #zone_id: \"21ff0e36-1624-4c18-be2f-070513079185\"\n        state: \"present\"\n      with_items:\n        - \"{{transportzones}}\"\n\n    # - name: Create logical switch\n    #   nsxt_logical_switches:\n    #     hostname: \"{{hostname}}\"\n    #     username: \"{{username}}\"\n    #     password: \"{{password}}\"\n    #     validate_certs: False\n    #     display_name: \"test_lswitch\"\n    #     replication_mode: SOURCE\n    #     admin_state: UP\n    #     transport_zone_id: \"{{transport_zone.id}}\"\n    #     state: \"present\"\n    #   register: logical_switch\n\n    - name: Create uplink profile\n      vmware.ansible_for_nsxt.nsxt_uplink_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: UplinkHostSwitchProfile\n        display_name: \"{{item.display_name}}\"\n        mtu: 1600\n        teaming: \"{{item.teaming}}\"\n        transport_vlan: \"{{item.transport_vlan}}\"\n        state: \"present\"\n      with_items:\n        - \"{{uplink_profiles}}\"\n\n    - name: Create transport node\n      vmware.ansible_for_nsxt.nsxt_transport_nodes:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: TransportNode\n        display_name: \"{{item.display_name}}\"\n        description: NSX configured Test Transport Node\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        transport_zone_endpoints: \"{{item.transport_zone_endpoints}}\"\n        fabric_node_name: \"{{item.fabric_node_name}}\"\n        state: present\n      with_items:\n        - \"{{transport_nodes}}\"\n\n#- debug: var=deploy_nsx_ova\n"
  },
  {
    "path": "tests/playbooks/mp/test_basic_topology_9x.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile_9x.yml\n  tasks:\n    - name: deploy NSX Manager OVA\n      vmware.ansible_for_nsxt.nsxt_deploy_ova:\n        ovftool_path: \"/usr/bin\"\n        datacenter: \"private_dc\"\n        datastore: \"data store\"\n        portgroup: \"VM Network\"\n        cluster: \"nsxt_cluster\"\n        vmname: \"nsxt-manager\"\n        hostname: \"nsxt-manager-10\"\n        dns_server: \"20.162.244.213\"\n        dns_domain: \"eng.vmware.com\"\n        ntp_server: \"123.110.200.124\"\n        gateway: \"10.112.203.253\"\n        ip_address: \"40.112.201.24\"\n        netmask: \"255.255.224.0\"\n        admin_password: \"Admin!23Admin\"\n        cli_password: \"Admin!23Admin\"\n        path_to_ova: \"http://build-squid.vcfd.broadcom.net/build/mts/release/bora-24563316/publish/nsx-unified-appliance/exports/ovf\"\n        ova_file: \"nsx-unified-appliance-9.0.0.0.24562919.ovf\"\n        vcenter: \"10.162.72.205\"\n        vcenter_user: \"administrator@vsphere.local\"\n        vcenter_passwd: \"Admin!23\"\n        deployment_size: \"small\"\n        role: \"NSX Manager\"\n#        role: \"nsx-manager nsx-controller\"\n\n    - name: Check manager status\n      vmware.ansible_for_nsxt.nsxt_manager_status:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: False\n          wait_time: 50\n\n    - name: Deploy compute manager\n      vmware.ansible_for_nsxt.nsxt_fabric_compute_managers:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: False\n          display_name: \"VC1\"\n          server: \"10.162.72.205\"\n          origin_type: vCenter\n          credential:\n            credential_type: UsernamePasswordLoginCredential\n            username: \"administrator@vsphere.local\"\n            password: \"Admin!23\"\n            thumbprint: \"36:43:34:D9:C2:06:27:4B:EE:C3:4A:AE:23:BF:76:A0:0C:4D:D6:8A:D3:16:55:97:62:07:C2:84:0C:D8:BA:66\"\n          state: present\n      register: compute_manager\n\n#    - name: Deploy controller\n#      vmware.ansible_for_nsxt.nsxt_controllers:\n#          hostname: \"{{hostname}}\"\n#          username: \"{{username}}\"\n#          password: \"{{password}}\"\n#          validate_certs: False\n#          deployment_requests:\n#          - roles:\n#            - CONTROLLER\n#            form_factor: \"MEDIUM\"\n#            user_settings:\n#              cli_password: \"Admin!23Admin\"\n#              root_password: \"Admin!23Admin\"\n#            deployment_config:\n#              placement_type: VsphereClusterNodeVMDeploymentConfig\n#              vc_id: \"{{compute_manager.id}}\"\n#              management_network_id: \"network-44\"\n#              hostname: \"controller-1\"\n#              compute_id: \"domain-c49\"\n#              storage_id: \"datastore-43\"\n#              default_gateway_addresses:\n#              - 11.122.203.253\n#              management_port_subnets:\n#              - ip_addresses:\n#                - 11.142.201.25\n#                prefix_length: \"19\"\n#          clustering_config:\n#            clustering_type: ControlClusteringConfig\n#            shared_secret: \"123456\"\n#            join_to_existing_cluster: false\n#          state: present\n\n    - name: Create ip pool\n      vmware.ansible_for_nsxt.nsxt_policy_ip_pool:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        pool_static_subnets: \"{{item.pool_static_subnets}}\"\n        state: present\n      with_items:\n        - \"{{ip_pools}}\"\n\n    - name: Create transport zone\n      vmware.ansible_for_nsxt.nsxt_transport_zones:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: \"TransportZone\"\n        display_name: \"{{item.display_name}}\"\n        description: \"NSX configured Test Transport Zone\"\n        tz_type: \"{{item.tz_type}}\"\n        #zone_id: \"21ff0e36-1624-4c18-be2f-070513079185\"\n        state: \"present\"\n      with_items:\n        - \"{{transportzones}}\"\n\n    # - name: Create logical switch\n    #   nsxt_logical_switches:\n    #     hostname: \"{{hostname}}\"\n    #     username: \"{{username}}\"\n    #     password: \"{{password}}\"\n    #     validate_certs: False\n    #     display_name: \"test_lswitch\"\n    #     replication_mode: SOURCE\n    #     admin_state: UP\n    #     transport_zone_id: \"{{transport_zone.id}}\"\n    #     state: \"present\"\n    #   register: logical_switch\n\n    - name: Create uplink profile\n      vmware.ansible_for_nsxt.nsxt_uplink_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: UplinkHostSwitchProfile\n        display_name: \"{{item.display_name}}\"\n        teaming: \"{{item.teaming}}\"\n        transport_vlan: \"{{item.transport_vlan}}\"\n        state: \"present\"\n      with_items:\n        - \"{{uplink_profiles}}\"\n\n    - name: Create transport node\n      vmware.ansible_for_nsxt.nsxt_transport_nodes:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        description: NSX configured Test Transport Node\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        node_deployment_info: \"{{item.node_deployment_info}}\"\n        state: present\n      with_items:\n        - \"{{host_transport_nodes}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_certificates.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Add a new certificate\n      vmware.ansible_for_nsxt.nsxt_certificates:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"Certificate_file\"\n        pem_encoded_file: \"/Path/to/certificate/file\"\n        #private_key_file: \"/Path/to/p12/private/key/file\"\n        state: \"present\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_certificates_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List all existing certificates\n      vmware.ansible_for_nsxt.nsxt_certificates_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes"
  },
  {
    "path": "tests/playbooks/mp/test_cluster_profiles.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Add edge cluster\n      vmware.ansible_for_nsxt.nsxt_cluster_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: EdgeHighAvailabilityProfile\n        display_name: edge-cluster-profile-East\n        description: \"Edge cluster profile description\"\n        bfd_probe_interval: 1000\n        bfd_declare_dead_multiple: 3\n        bfd_allowed_hops: 1\n        standby_relocation_config:\n          standby_relocation_threshold: 600\n        state: present\n"
  },
  {
    "path": "tests/playbooks/mp/test_cluster_profiles_facts.yml",
    "content": "# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List all cluster profiles\n      vmware.ansible_for_nsxt.nsxt_cluster_profiles_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_compute_managers.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Register compute manager\n      vmware.ansible_for_nsxt.nsxt_fabric_compute_managers:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: False\n          #compute_manager_id: \"25d314b6-97f2-48e2-87b5-f9ce04caf5f8\"\n          display_name: \"{{item.display_name}}\"\n          server: \"{{item.server}}\"\n          origin_type: \"{{item.origin_type}}\"\n          credential:\n            credential_type: \"{{item.credential_type}}\"\n            username: \"{{item.username}}\"\n            password: \"{{item.password}}\"\n            thumbprint: \"{{item.thumbprint}}\"\n          state: present\n      with_items:\n        - \"{{compute_managers}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_compute_managers_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List all compute managers\n      vmware.ansible_for_nsxt.nsxt_fabric_compute_managers_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_configure_transport_node.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile_tn.yml\n  tasks:\n\n    - name: Create ip pool\n      vmware.ansible_for_nsxt.nsxt_ip_pools:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        subnets: \"{{item.subnets}}\"\n        state: present\n      with_items:\n        - \"{{ip_pools}}\"\n\n    - name: Create transport zone\n      vmware.ansible_for_nsxt.nsxt_transport_zones:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: \"TransportZone\"\n        display_name: \"{{item.display_name}}\"\n        description: \"NSX configured Test Transport Zone\"\n        transport_type: \"{{item.transport_type}}\"\n        host_switch_name: \"{{item.host_switch_name}}\"\n        state: \"present\"\n      with_items:\n        - \"{{transportzones}}\"\n\n    - name: Create uplink profile\n      vmware.ansible_for_nsxt.nsxt_uplink_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: UplinkHostSwitchProfile\n        display_name: \"{{item.display_name}}\"\n        mtu: 1600\n        teaming: \"{{item.teaming}}\"\n        transport_vlan: \"{{item.transport_vlan}}\"\n        state: \"present\"\n      with_items:\n        - \"{{uplink_profiles}}\"\n\n    - name: Create transport node\n      vmware.ansible_for_nsxt.nsxt_transport_nodes:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        transport_zone_endpoints: \"{{item.transport_zone_endpoints}}\"\n        node_deployment_info: \"{{item.node_deployment_info}}\"\n        state: present\n      with_items:\n        - \"{{transport_nodes}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_configure_transport_node_9x.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile_tn_9x.yml\n  tasks:\n\n    - name: Create ip pool\n      vmware.ansible_for_nsxt.nsxt_policy_ip_pool:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        pool_static_subnets: \"{{item.pool_static_subnets}}\"\n        state: present\n      with_items:\n        - \"{{ip_pools}}\"\n\n    - name: Create transport zone\n      vmware.ansible_for_nsxt.nsxt_transport_zones:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: \"TransportZone\"\n        display_name: \"{{item.display_name}}\"\n        description: \"NSX configured Test Transport Zone\"\n        tz_type: \"{{item.tz_type}}\"\n        state: \"present\"\n      with_items:\n        - \"{{transportzones}}\"\n\n    - name: Create uplink profile\n      vmware.ansible_for_nsxt.nsxt_uplink_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: UplinkHostSwitchProfile\n        display_name: \"{{item.display_name}}\"\n        mtu: 1600\n        teaming: \"{{item.teaming}}\"\n        transport_vlan: \"{{item.transport_vlan}}\"\n        state: \"present\"\n      with_items:\n        - \"{{uplink_profiles}}\"\n\n    - name: Create transport node\n      vmware.ansible_for_nsxt.nsxt_transport_nodes:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        node_deployment_info: \"{{item.node_deployment_info}}\"\n        state: present\n      with_items:\n        - \"{{transport_nodes}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_edge_clusters.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Add edge cluster\n      vmware.ansible_for_nsxt.nsxt_edge_clusters:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: edge-cluster-1\n        cluster_profile_bindings:\n        - profile_name: \"Profile01\"\n          resource_type: EdgeHighAvailabilityProfile\n        members:\n        - transport_node_name: \"TN_1\"\n        state: present\n"
  },
  {
    "path": "tests/playbooks/mp/test_edge_clusters_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List edge clusters\n      vmware.ansible_for_nsxt.nsxt_edge_clusters_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_global_manager_enable_service.yml",
    "content": "---\n#\n# Playbook to register Compute Managers with NSX Appliance\n#\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Make the global manager as Active\n      vmware.ansible_for_nsxt.nsxt_global_manager_enable_service:\n          hostname: \"{{ global_managers[0].fqdn }}\"\n          username: \"{{ global_managers[0].username }}\"\n          password: \"{{ global_managers[0].password }}\"\n          validate_certs: \"{{ validate_certs }}\"\n          id: \"{{ global_managers[0].id }}\"\n          display_name: \"{{ global_managers[0].display_name }}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_global_manager_registration.yml",
    "content": "---\n#\n# Playbook to register Compute Managers with NSX Appliance\n#\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Register global manager\n      vmware.ansible_for_nsxt.nsxt_global_manager_registration:\n          hostname: \"{{ hostname }}\"\n          username: \"{{ username }}\"\n          password: \"{{ password }}\"\n          validate_certs: \"{{ validate_certs }}\"\n          display_name: \"{{ item.display_name }}\"\n          mode: \"{{ item.mode }}\"\n          connection_info:\n            fqdn: \"{{ item.fqdn }}\"\n            username: \"{{ item.username }}\"\n            password: \"{{ item.password }}\"\n            thumbprint: \"{{ item.thumbprint }}\"\n          state: absent\n      with_items:\n        - \"{{global_managers}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_global_managers_active.yml",
    "content": "---\n#\n# Playbook to register Compute Managers with NSX Appliance\n#\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Make the global manager as Active\n      vmware.ansible_for_nsxt.nsxt_global_manager_active:\n          hostname: \"{{ global_managers[0].fqdn }}\"\n          username: \"{{ global_managers[0].username }}\"\n          password: \"{{ global_managers[0].password }}\"\n          validate_certs: \"{{ validate_certs }}\"\n          id: \"{{ global_managers[0].id }}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_ip_blocks.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create ip block\n      vmware.ansible_for_nsxt.nsxt_ip_blocks:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"MyDisplayname\"\n        cidr: \"192.168.0.0/16\"\n        state: present\n"
  },
  {
    "path": "tests/playbooks/mp/test_ip_blocks_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List IP address block\n      vmware.ansible_for_nsxt.nsxt_ip_blocks_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n"
  },
  {
    "path": "tests/playbooks/mp/test_ip_pools.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create ip pool\n      vmware.ansible_for_nsxt.nsxt_ip_pools:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        subnets: \"{{item.subnets}}\"\n        state: present\n      with_items:\n        - \"{{ip_pools}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_ip_pools_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List IP pools\n      vmware.ansible_for_nsxt.nsxt_ip_pools_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_licenses.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Add license\n      vmware.ansible_for_nsxt.nsxt_licenses:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        license_key: \"00000-00000-00000-00000-00000\"\n        state: \"present\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_licenses_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Get all licenses\n      vmware.ansible_for_nsxt.nsxt_licenses_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_local_manager_registration.yml",
    "content": "---\n#\n# Playbook to register Compute Managers with NSX Appliance\n#\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Register local manager\n      vmware.ansible_for_nsxt.nsxt_local_manager_registration:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: \"{{ validate_certs }}\"\n          display_name: \"{{ item.display_name }}\"\n          id: \"{{ item.id }}\"\n          site_connection_info:\n            fqdn: \"{{ item.fqdn }}\"\n            username: \"{{ item.username }}\"\n            password: \"{{ item.password }}\"\n            thumbprint: \"{{ item.thumbprint }}\"\n          state: absent\n      with_items:\n        - \"{{local_managers}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_local_managers_compatibility.yml",
    "content": "---\n#\n# Playbook to register Compute Managers with NSX Appliance\n#\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Checks the compatibility of a local manager for registration with a global manager\n      vmware.ansible_for_nsxt.nsxt_local_managers_compatibility:\n          hostname: \"{{ hostname }}\"\n          username: \"{{ username }}\"\n          password: \"{{ password }}\"\n          validate_certs: \"{{ validate_certs }}\"\n          site_connection_info:\n            fqdn: \"{{ local_managers[0].fqdn }}\"\n            username: \"{{ local_managers[0].username }}\"\n            password: \"{{ local_managers[0].password }}\"\n            thumbprint: \"{{ local_managers[0].thumbprint }}\"\n      register: task_output\n    - debug:\n        var: task_output.version_compatible\n"
  },
  {
    "path": "tests/playbooks/mp/test_local_managers_facts.yml",
    "content": "---\n#\n# Playbook to get facts of local managers registered with a global manager\n#\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Register local manager\n      vmware.ansible_for_nsxt.nsxt_local_managers_facts:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: \"{{ validate_certs }}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_logical_ports.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create a Logical Port\n      vmware.ansible_for_nsxt.nsxt_logical_ports:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"logical_port_1\"\n        logical_switch_name: \"ls1\"\n        attachment:\n          attachment_type: \"VIF\"\n          id: \"vif2\"\n        admin_state: \"UP\"\n        state: \"present\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_logical_ports_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List logical ports\n      vmware.ansible_for_nsxt.nsxt_logical_ports_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_logical_router_ports.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create logical router port\n      vmware.ansible_for_nsxt.nsxt_logical_router_ports:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"lrouterport-103\"\n        resource_type: \"LogicalRouterDownLinkPort\"\n        logical_router_name: \"tier-0\"\n        linked_logical_switch_port_id:\n          target_type: \"LogicalPort\"\n          target_id: \"fa535fbd-c01f-4536-86e4-36ee3572b6f3\"\n        subnets:\n        - ip_addresses:\n          - 192.168.3.1\n          prefix_length: 24\n        state: \"present\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_logical_router_ports_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List logical router ports\n      vmware.ansible_for_nsxt.nsxt_logical_router_ports_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_logical_router_static_route.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Add Static Routes on a Logical Router\n      vmware.ansible_for_nsxt.nsxt_logical_router_static_routes:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"static_route\"\n        logical_router_name: \"tier-0\"\n        next_hops:\n        - administrative_distance: '2'\n          ip_address: 192.168.200.254\n        network: 192.168.200.0/24\n        state: \"present\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_logical_routers.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create logical router\n      vmware.ansible_for_nsxt.nsxt_logical_routers:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"tier-0\"\n        edge_cluster_name: \"edge-cluster-1\"\n        router_type: \"TIER0\"\n        high_availability_mode: \"ACTIVE_ACTIVE\"\n        state: \"present\"\n        failover_mode: \"NON_PREEMPTIVE\"\n        advanced_config:\n          internal_transit_network: \"169.254.0.0/28\"\n          ha_vip_configs:\n            - enabled: False\n              ha_vip_subnets:\n                - active_vip_addresses: [ \"12.12.4.4\" ]\n                  prefix_length: \"22\"\n              redundant_uplink_port_ids: [ \"Uplink-1\",\"Uplink-2\" ]\n            - enabled: False\n              ha_vip_subnets:\n                - active_vip_addresses: [ \"12.12.4.5\" ]\n                  prefix_length: \"22\"\n              redundant_uplink_port_names: [ \"Uplink-3\",\"Uplink-4\" ]\n              redundant_uplink_port_ids: [\"z\", \"y\"]\n        tags:\n          - scope: \"Scope1\"\n            tag: \"Tag1\""
  },
  {
    "path": "tests/playbooks/mp/test_logical_routers_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List Logical Routers\n      vmware.ansible_for_nsxt.nsxt_logical_routers_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_logical_switches.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create logical switch\n      vmware.ansible_for_nsxt.nsxt_logical_switches:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"ls1\"\n        replication_mode: SOURCE\n        admin_state: UP\n        transport_zone_name: \"TZ1\"\n        state: \"present\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_logical_switches_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List All Logical Switches\n      vmware.ansible_for_nsxt.nsxt_logical_switches_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_manager_auto_deployment.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Deploy and register a cluster node VM\n      vmware.ansible_for_nsxt.nsxt_manager_auto_deployment:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: False\n          deployment_requests:\n          - roles:\n            - CONTROLLER\n            - MANAGER\n            form_factor: \"SMALL\"\n            user_settings:\n              cli_password: \"Admin!23Admin\"\n              root_password: \"Admin!23Admin\"\n              audit_password: \"Admin!23Admin\"\n            deployment_config:\n              ignore_ssl_verification: False\n              placement_type: VsphereClusterNodeVMDeploymentConfig\n              vc_name: \"VC1\"\n              vc_username: \"administrator@vsphere.local\"\n              vc_password: \"Admin!23\"\n              management_network: \"VM Network\"\n              hostname: \"manager5.vmware.com\"\n              compute: \"HostCluster\"\n              storage: \"datastore01\"\n              disk_provisioning: \"THIN\"\n              default_gateway_addresses:\n                - 10.176.135.253\n              management_port_subnets:\n                - ip_addresses:\n                    - 10.176.132.57\n                  prefix_length: \"19\"\n              dns_servers:\n                - 10.172.40.1\n                - FD01:1:3:1001::10\n              management_port_ipv6_subnets:\n                - ip_addresses:\n                    - 2620:124:6020:1045::1b\n                  prefix_length: \"64\"\n              default_ipv6_gateway_addresses:\n                - 2620:124:6020:1045::253\n          #node_id: 7503e86e-c502-46fc-8d91-45a06d314d88\n          state: present\n"
  },
  {
    "path": "tests/playbooks/mp/test_manager_auto_deployment_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Lists info for all cluster node VM auto-deployment\n      vmware.ansible_for_nsxt.nsxt_manager_auto_deployment_facts:\n          hostname: \"{{hostname}}\"\n          username: \"{{username}}\"\n          password: \"{{password}}\"\n          validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_manager_status.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Check manager status\n      vmware.ansible_for_nsxt.nsxt_manager_status:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        wait_time: 30\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_ovf_deployment.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: deploy NSX Manager OVA\n      vmware.ansible_for_nsxt.nsxt_deploy_ova:\n        ovftool_path: \"/usr/bin\"\n        #folder: 'folder-os-datacenter'\n        datacenter: \"os-datacenter\"\n        datastore: \"datastore\"\n        portgroup: \"VM Network\"\n        cluster: \"os-compute-cluster-1\"\n        vmname: \"nsxt-manager\"\n        hostname: \"nsxt-manager-10\"\n        dns_server: \"10.172.40.1 FD01:1:3:1001::10\"\n        dns_domain: \"eng.vmware.com\"\n        ntp_server: \"10.172.40.1 FD01:1:3:1001::10\"\n        gateway: \"10.176.135.253\"\n        gateway6_0: \"2620:124:6020:1045::253\"\n        ip_address: \"10.176.132.59\"\n        ip_address6_0: \"2620:124:6020:1045::1a\"\n        netmask: \"255.255.252.0\"\n        netmask6_0: \"64\"\n        admin_password: \"Admin!23Admin\"\n        cli_password: \"Admin!23Admin\"\n        path_to_ova: \"http://build-squid.eng.vmware.com/build/mts/release/bora-19956989/publish/nsx-unified-appliance/exports/ovf\"\n        ova_file: \"nsx-unified-appliance-4.0.1.0.0.19956985.ovf\"\n        vcenter: \"10.176.132.1\"\n        vcenter_user: \"administrator@vsphere.local\"\n        vcenter_passwd: \"Admin!23\"\n        deployment_size: \"small\"\n        role: \"NSX Manager\"\n        ssh_enabled: true\n        allow_ssh_root_login: true\n        disk_mode: thin\n        ip_protocol: IPv6\n\n\n"
  },
  {
    "path": "tests/playbooks/mp/test_principal_identities.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Register a name-certificate combination\n      vmware.ansible_for_nsxt.nsxt_principal_identities:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"Principal_display_name\"\n        description: 'Foo bar'\n        certificate_name: 'Certificate_file'\n        name: \"Principal_name\"\n        certificate_pem_file: \"/Path/to/cert/file\"\n        is_protected: True\n        node_id: \"node-1\"\n        role: \"enterprise_admin\"\n        #certificate_name: \"Certificate_file\"\n        state: \"absent\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_principal_identities_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List all existing principal identities\n      vmware.ansible_for_nsxt.nsxt_principal_identities_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes"
  },
  {
    "path": "tests/playbooks/mp/test_repo_sync.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Get repo sync status of an auto deployed node\n      vmware.ansible_for_nsxt.nsxt_repo_sync:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False"
  },
  {
    "path": "tests/playbooks/mp/test_repo_sync_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Get repo sync status of an auto deployed node\n      vmware.ansible_for_nsxt.nsxt_repo_sync_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        node_name: \"manager-node02\""
  },
  {
    "path": "tests/playbooks/mp/test_rest.yml",
    "content": "# Test code for the nsxt_rest module.\n# Copyright: (c) 2020, sky-joker <sky.jokerxx@gmail.com>\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n---\n- hosts: 127.0.0.1\n  gather_facts: no\n  vars:\n    nsxt_hostname: nsxt-manager-01\n    nsxt_username: admin\n    nsxt_password: password\n  tasks:\n    - name: create a new segment\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: patch\n        path: /policy/api/v1/infra/segments/segment\n        content:\n          {\n            \"display_name\": \"segment\",\n            \"subnets\": [\n              {\n                \"gateway_address\": \"192.168.0.1/24\"\n              }\n            ],\n          }\n      register: create_new_segment_result\n\n    - assert:\n        that:\n          - create_new_segment_result.changed is sameas true\n          - create_new_segment_result.body is defined\n          - create_new_segment_result.body | length >= 1\n          - create_new_segment_result.body.id == \"segment\"\n          - create_new_segment_result.body.subnets.0.gateway_address == \"192.168.0.1/24\"\n\n    - name: create a new segment(again - expectation no change will occur)\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: patch\n        path: /policy/api/v1/infra/segments/segment\n        content:\n          {\n            \"display_name\": \"segment\",\n            \"subnets\": [\n              {\n                \"gateway_address\": \"192.168.0.1/24\"\n              }\n            ],\n          }\n      register: create_new_segment_again_result\n\n    - assert:\n        that:\n          - create_new_segment_again_result.changed is sameas false\n          - create_new_segment_again_result.body is defined\n          - create_new_segment_again_result.body | length >= 1\n          - create_new_segment_again_result.body.id == \"segment\"\n          - create_new_segment_again_result.body.subnets.0.gateway_address == \"192.168.0.1/24\"\n\n    - name: update segment parameter\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: patch\n        path: /policy/api/v1/infra/segments/segment\n        content:\n          {\n            \"display_name\": \"segment\",\n            \"subnets\": [\n              {\n                \"gateway_address\": \"192.168.0.2/24\"\n              }\n            ],\n          }\n      register: update_segment_parameter_result\n\n    - assert:\n        that:\n          - update_segment_parameter_result.changed is sameas true\n          - update_segment_parameter_result.body is defined\n          - update_segment_parameter_result.body | length >= 1\n          - update_segment_parameter_result.body.id == \"segment\"\n          - update_segment_parameter_result.body.subnets.0.gateway_address == \"192.168.0.2/24\"\n\n    - name: update segment parameter(again - expectation no change will occur)\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: patch\n        path: /policy/api/v1/infra/segments/segment\n        content:\n          {\n            \"display_name\": \"segment\",\n            \"subnets\": [\n              {\n                \"gateway_address\": \"192.168.0.2/24\"\n              }\n            ],\n          }\n      register: update_segment_parameter_again_result\n\n    - assert:\n        that:\n          - update_segment_parameter_again_result.changed is sameas false\n          - update_segment_parameter_again_result.body is defined\n          - update_segment_parameter_again_result.body | length >= 1\n          - update_segment_parameter_again_result.body.id == \"segment\"\n          - update_segment_parameter_again_result.body.subnets.0.gateway_address == \"192.168.0.2/24\"\n\n    - name: get segment information\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: get\n        path: /policy/api/v1/infra/segments/segment\n      register: get_segment_information_result\n\n    - assert:\n        that:\n          - get_segment_information_result.changed is sameas false\n          - get_segment_information_result.body is defined\n          - get_segment_information_result.body | length >= 1\n          - get_segment_information_result.body.id == \"segment\"\n          - get_segment_information_result.body.subnets.0.gateway_address == \"192.168.0.2/24\"\n\n    - name: delete a segment\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: delete\n        path: /policy/api/v1/infra/segments/segment\n      register: delete_segment_result\n\n    - assert:\n        that:\n          - delete_segment_result.changed is sameas true\n\n    - name: delete a segment(again - expectation no change will occur)\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: delete\n        path: /policy/api/v1/infra/segments/segment\n      register: delete_segment_again_result\n\n    - assert:\n        that:\n          - delete_segment_again_result.changed is sameas false\n\n    - name: create json file for segment parameter\n      copy:\n        content:\n          {\n            \"display_name\": \"segment\",\n            \"subnets\": [\n              {\n                \"gateway_address\": \"192.168.0.1/24\"\n              }\n            ],\n          }\n        dest: segment_parametr.json\n      register: create_json_file_result\n\n    - assert:\n        that:\n          - create_json_file_result.changed is sameas true\n\n    - name: create a new segment with json file\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: patch\n        path: /policy/api/v1/infra/segments/segment\n        src: segment_parametr.json\n      register: create_new_segment_result\n\n    - assert:\n        that:\n          - create_new_segment_result.changed is sameas true\n          - create_new_segment_result.body is defined\n          - create_new_segment_result.body | length >= 1\n          - create_new_segment_result.body.id == \"segment\"\n          - create_new_segment_result.body.subnets.0.gateway_address == \"192.168.0.1/24\"\n\n    - name: create a new segment with json file(again - expectation no change will occur)\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: patch\n        path: /policy/api/v1/infra/segments/segment\n        src: segment_parametr.json\n      register: create_new_segment_again_result\n\n    - assert:\n        that:\n          - create_new_segment_again_result.changed is sameas false\n          - create_new_segment_again_result.body is defined\n          - create_new_segment_again_result.body | length >= 1\n          - create_new_segment_again_result.body.id == \"segment\"\n          - create_new_segment_again_result.body.subnets.0.gateway_address == \"192.168.0.1/24\"\n\n    - name: update json file for segment parameter\n      copy:\n        content:\n          {\n            \"display_name\": \"segment\",\n            \"subnets\": [\n              {\n                \"gateway_address\": \"192.168.0.2/24\"\n              }\n            ],\n          }\n        dest: segment_parametr.json\n      register: update_json_file_result\n\n    - assert:\n        that:\n          - update_json_file_result.changed is sameas true\n\n    - name: update segment parameter\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: patch\n        path: /policy/api/v1/infra/segments/segment\n        src: segment_parametr.json\n      register: update_segment_parameter_result\n\n    - assert:\n        that:\n          - update_segment_parameter_result.changed is sameas true\n          - update_segment_parameter_result.body is defined\n          - update_segment_parameter_result.body | length >= 1\n          - update_segment_parameter_result.body.id == \"segment\"\n          - update_segment_parameter_result.body.subnets.0.gateway_address == \"192.168.0.2/24\"\n\n    - name: update segment parameter(again - expectation no change will occur)\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: patch\n        path: /policy/api/v1/infra/segments/segment\n        src: segment_parametr.json\n      register: update_segment_parameter_again_result\n\n    - assert:\n        that:\n          - update_segment_parameter_again_result.changed is sameas false\n          - update_segment_parameter_again_result.body is defined\n          - update_segment_parameter_again_result.body | length >= 1\n          - update_segment_parameter_again_result.body.id == \"segment\"\n          - update_segment_parameter_again_result.body.subnets.0.gateway_address == \"192.168.0.2/24\"\n\n    - name: delete a segment\n      vmware.ansible_for_nsxt.nsxt_rest:\n        hostname: \"{{ nsxt_hostname }}\"\n        username: \"{{ nsxt_username }}\"\n        password: \"{{ nsxt_password }}\"\n        validate_certs: false\n        method: delete\n        path: /policy/api/v1/infra/segments/segment\n      register: delete_segment_result\n\n    - assert:\n        that:\n          - delete_segment_result.changed is sameas true\n"
  },
  {
    "path": "tests/playbooks/mp/test_route_advertise.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Toggle tier 1 route advertisement\n      vmware.ansible_for_nsxt.nsxt_route_advertise:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        display_name: \"{{item.display_name}}\"\n        validate_certs: False\n        enabled: \"{{item.enabled}}\"\n        advertise_dns_forwarder: \"{{item.advertise_dns_forwarder}}\"\n        advertise_lb_snat_ip: \"{{item.advertise_lb_snat_ip}}\"\n        advertise_lb_vip: \"{{item.advertise_lb_vip}}\"\n        advertise_nat_routes: \"{{item.advertise_nat_routes}}\"\n        advertise_nsx_connected_routes: \"{{item.advertise_nsx_connected_routes}}\"\n        advertise_static_routes: \"{{item.advertise_static_routes}}\"\n      with_items:\n        - \"{{route_advertise}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_transport_node_collections.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Attach Transport node profile to cluster\n      vmware.ansible_for_nsxt.nsxt_transport_node_collections:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"TNC1\"\n        resource_type: \"TransportNodeCollection\"\n        description: \"Transport Node Collections 1\"\n        compute_manager_name: \"VC1\"\n        cluster_name: \"os-compute-cluster-1\"\n        transport_node_profile_name: \"TNP1\"\n        state: present\n"
  },
  {
    "path": "tests/playbooks/mp/test_transport_node_collections_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List Transport Node collections\n      vmware.ansible_for_nsxt.nsxt_transport_node_collections_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_transport_node_profiles.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create transport node profile \n      vmware.ansible_for_nsxt.nsxt_transport_node_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: TransportNodeProfile\n        display_name: \"{{item.display_name}}\"\n        description: NSX configured Test Transport Node Profile\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        state: present\n      with_items:\n        - \"{{transport_node_profiles}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_transport_node_profiles_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List transport node profiles\n      vmware.ansible_for_nsxt.nsxt_transport_node_profiles_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_transport_nodes.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create transport node\n      vmware.ansible_for_nsxt.nsxt_transport_nodes:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        node_deployment_info: \"{{item.node_deployment_info}}\"\n          # Host node deployment info\n          # resource_type: \"{{item.node_deployment_info.resource_type}}\"\n          # display_name: \"{{item.node_deployment_info.display_name}}\"\n          # ip_addresses: \"{{item.node_deployment_info.ip_addresses}}\"\n          # os_type: \"{{item.node_deployment_info.os_type}}\"\n          # os_version: \"{{item.node_deployment_info.os_version}}\"\n          # host_credential:\n          #   username: \"{{item.node_deployment_info.host_credential.username}}\"\n          #   password: \"{{item.node_deployment_info.host_credential.password}}\"\n          #   thumbprint: \"{{item.node_deployment_info.host_credential.thumbprint}}\"\n          # Edge node deployment info\n          # resource_type: \"{{item.node_deployment_info.resource_type}}\"\n          # display_name: \"{{item.node_deployment_info.display_name}}\"\n          # ip_addresses: \"{{item.node_deployment_info.ip_addresses}}\"\n          # deployment_type: \"{{item.node_deployment_info.deployment_type}}\"\n          # deployment_config:\n          #   form_factor: \"{{item.node_deployment_info.deployment_config.form_factor}}\"\n          #   node_user_settings:\n          #     cli_password: \"{{item.node_deployment_info.deployment_config.node_user_settings.cli_password}}\"\n          #     root_password: \"{{item.node_deployment_info.deployment_config.node_user_settings.root_password}}\"\n          #   vm_deployment_config:\n          #     placement_type: \"{{item.node_deployment_info.deployment_config.vm_deployment_config.placement_type}}\"\n          #     vc_id: \"{{item.node_deployment_info.deployment_config.vm_deployment_config.vc_id}}\"\n          #     data_network_ids: \"{{item.node_deployment_info.deployment_config.vm_deployment_config.data_network_ids}}\"\n          #     management_network_id: \"{{item.node_deployment_info.deployment_config.vm_deployment_config.management_network_id}}\"\n          #     hostname: \"{{item.node_deployment_info.deployment_config.vm_deployment_config.hostname}}\"\n          #     compute_id: \"{{item.node_deployment_info.deployment_config.vm_deployment_config.compute_id}}\"\n          #     storage_id: \"{{item.node_deployment_info.deployment_config.vm_deployment_config.storage_id}}\"\n          #     host_id: \"{{item.node_deployment_info.deployment_config.vm_deployment_config.host_id}}\"\n          #     default_gateway_addresses: \"{{item.node_deployment_info.deployment_config.vm_deployment_config.default_gateway_addresses}}\"\n              # management_port_subnets:\n              # - ip_addresses: \"{{item.node_deployment_info.deployment_config.vm_deployment_config.management_port_subnets.ip_addresses}}\"\n              #   prefix_length: \"{{item.node_deployment_info.deployment_config.vm_deployment_config.management_port_subnets.prefix_length}}\"\n        state: present\n      with_items:\n        - \"{{host_transport_nodes}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_transport_nodes_edge.yml",
    "content": "# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  tasks:\n    - name: Create edge transport nodes\n      vmware.ansible_for_nsxt.nsxt_transport_nodes:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{display_name}}\"\n        description: \"Edge transport node ansible\"\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        transport_zone_endpoints: \"{{item.transport_zone_endpoints}}\"\n        node_deployment_info: \"{{item.node_deployment_info}}\"\n        state: present\n      with_items:\n        - \"{{edge_transport_nodes}}\""
  },
  {
    "path": "tests/playbooks/mp/test_transport_nodes_edge_9x.yml",
    "content": "# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile_9x.yml\n  tasks:\n    - name: Create edge transport nodes\n      vmware.ansible_for_nsxt.nsxt_transport_nodes:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        description: \"Edge transport node ansible\"\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        node_deployment_info: \"{{item.node_deployment_info}}\"\n        state: present\n      with_items:\n        - \"{{edge_transport_nodes}}\""
  },
  {
    "path": "tests/playbooks/mp/test_transport_nodes_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List Transport Nodes\n      vmware.ansible_for_nsxt.nsxt_transport_nodes_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_transport_nodes_host.yml",
    "content": "# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create transport nodes\n      vmware.ansible_for_nsxt.nsxt_transport_nodes:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        description: \"Transport node with host\"\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        transport_zone_endpoints: \"{{item.transport_zone_endpoints}}\"\n        node_deployment_info: \"{{item.node_deployment_info}}\"\n        state: present\n      with_items:\n        - \"{{host_transport_nodes}}\""
  },
  {
    "path": "tests/playbooks/mp/test_transport_nodes_host_9x.yml",
    "content": "# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile_9x.yml\n  tasks:\n    - name: Create transport nodes\n      vmware.ansible_for_nsxt.nsxt_transport_nodes:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"{{item.display_name}}\"\n        description: \"Transport node with host\"\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{item.host_switches}}\"\n        node_deployment_info: \"{{item.node_deployment_info}}\"\n        state: present\n      with_items:\n        - \"{{host_transport_nodes}}\""
  },
  {
    "path": "tests/playbooks/mp/test_transport_zones.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create transport zone\n      vmware.ansible_for_nsxt.nsxt_transport_zones:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: \"PolicyTransportZone\"\n        display_name: \"{{item.display_name}}\"\n        description: \"NSX configured Test Transport Zone\"\n        tz_type: \"{{item.tz_type}}\"\n        state: \"present\"\n        is_default: false\n        nested_nsx: False\n      register: result\n      with_items:\n        - \"{{transportzones}}\"\n    - debug: var=result.id\n"
  },
  {
    "path": "tests/playbooks/mp/test_transport_zones_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List Transport Zones\n      vmware.ansible_for_nsxt.nsxt_transport_zones_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_eula_accept.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Accepts EULA\n      vmware.ansible_for_nsxt.nsxt_upgrade_eula_accept:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_eula_accept_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Retrieve information about EULA acceptance\n      vmware.ansible_for_nsxt.nsxt_upgrade_eula_accept_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        required_info: 'acceptance'"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_groups.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create upgrade groups\n      vmware.ansible_for_nsxt.nsxt_upgrade_groups:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        display_name: \"TestGroupAnsible\"\n        type: \"HOST\"\n        parallel: \"true\"\n        enabled: \"true\"\n        upgrade_units:\n        - host_name: \"10.160.165.71\"\n        state: \"present\""
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_groups_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Get upgrade groups info\n      vmware.ansible_for_nsxt.nsxt_upgrade_groups_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_history_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Get upgrade history\n      vmware.ansible_for_nsxt.nsxt_upgrade_history:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_plan.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Update upgrade plan\n      vmware.ansible_for_nsxt.nsxt_upgrade_plan:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        component_type: 'host'\n        parallel: True\n        pause_after_each_group: True\n        pause_on_error: True\n        state: 'present'\n"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_plan_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Retrieve upgrade plan\n      vmware.ansible_for_nsxt.nsxt_upgrade_plan_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        component_type: 'host'"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_postchecks.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Run upgrade postchecks\n      vmware.ansible_for_nsxt.nsxt_upgrade_postchecks:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        timeout: 7200\n        component_type: 'host'\n"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_pre_post_checks_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Get upgrade pre and post checks info\n      vmware.ansible_for_nsxt.nsxt_upgrade_pre_post_checks_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_prechecks.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Run and abort upgrade prechecks\n      vmware.ansible_for_nsxt.nsxt_upgrade_prechecks:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        state: 'present'"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_run.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Runs Upgrade\n      vmware.ansible_for_nsxt.nsxt_upgrade_run:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        paused_upgrade: False"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_status_summary_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Get upgrade status summary\n      vmware.ansible_for_nsxt.nsxt_upgrade_status_summary_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_uc.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Upgrade UC\n      vmware.ansible_for_nsxt.nsxt_upgrade_uc:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_uc_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Get UC upgrade status\n      vmware.ansible_for_nsxt.nsxt_upgrade_uc_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_upload_mub.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Upload MUB to NSX-T Manager\n      vmware.ansible_for_nsxt.nsxt_upgrade_upload_mub:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        url: \"http://build-squid.eng.vmware.com/build/mts/release/bora-14179320/publish/upgrade/VMware-NSX-upgrade-bundle-2.5.0.0.0.14179320.mub\"\n        timeout: 9000"
  },
  {
    "path": "tests/playbooks/mp/test_upgrade_upload_mub_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Get info of uploaded MUB to NSX-T Manager \n      vmware.ansible_for_nsxt.nsxt_upgrade_upload_mub_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        bundle_id: \"2500014364090\""
  },
  {
    "path": "tests/playbooks/mp/test_uplink_profiles.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Create uplink profile\n      vmware.ansible_for_nsxt.nsxt_uplink_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: UplinkHostSwitchProfile\n        display_name: \"{{item.display_name}}\"\n        mtu: 1600\n        teaming: \"{{item.teaming}}\"\n        transport_vlan: \"{{item.transport_vlan}}\"\n        state: \"present\"\n      with_items:\n        - \"{{uplink_profiles}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_uplink_profiles_9x.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile_9x.yml\n  tasks:\n    - name: Create uplink profile\n      vmware.ansible_for_nsxt.nsxt_uplink_profiles:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        resource_type: UplinkHostSwitchProfile\n        display_name: \"{{item.display_name}}\"\n        teaming: \"{{item.teaming}}\"\n        transport_vlan: \"{{item.transport_vlan}}\"\n        state: \"present\"\n      with_items:\n        - \"{{uplink_profiles}}\"\n"
  },
  {
    "path": "tests/playbooks/mp/test_uplink_profiles_facts.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: List uplink profiles\n      vmware.ansible_for_nsxt.nsxt_uplink_profiles_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes\n"
  },
  {
    "path": "tests/playbooks/mp/test_vidm.yml",
    "content": "---\n#\n# Playbook to register Compute Managers with NSX Appliance\n#\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Register vidm to NSX\n      vmware.ansible_for_nsxt.nsxt_vidm:\n        hostname: \"{{ hostname }}\"\n        username: \"{{ username }}\"\n        password: \"{{ password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        client_id: \"{{ vidm.client_id }}\"\n        client_secret: \"{{ vidm.client_secret }}\"\n        host_name: \"{{ vidm.host_name }}\"\n        lb_enable: \"{{ vidm.lb_enable }}\"\n        node_host_name: \"{{ vidm.node_host_name }}\"\n        thumbprint: \"{{ vidm.thumbprint }}\"\n        state: absent"
  },
  {
    "path": "tests/playbooks/mp/test_virtual_ip.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Adds cluster virtual IP address\n      vmware.ansible_for_nsxt.nsxt_virtual_ip:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n        virtual_ip_address: \"10.186.94.5\"\n        virtual_ip6_address: \"2620:124:6020:c308::10\"\n        action: clear_virtual_ip\n        state: absent\n"
  },
  {
    "path": "tests/playbooks/mp/test_virtual_ip_facts.yml",
    "content": "# Copyright 2019 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - answerfile.yml\n  tasks:\n    - name: Get all configured cluster virtual IP address\n      vmware.ansible_for_nsxt.nsxt_virtual_ip_facts:\n        hostname: \"{{hostname}}\"\n        username: \"{{username}}\"\n        password: \"{{password}}\"\n        validate_certs: False\n      check_mode: yes"
  },
  {
    "path": "tests/playbooks/policy/test_nsxt_policy_bfd_profile.yaml",
    "content": "- hosts: localhost\n  tasks:\n    - name: Update BFD Profile\n      vmware.ansible_for_nsxt.nsxt_policy_bfd_profile:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        display_name: test-bfd-profile\n        state: present\n        interval: 200\n        multiple: 10\n"
  },
  {
    "path": "tests/playbooks/policy/test_nsxt_policy_gateway_policy.yml",
    "content": "# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to test Gateway Policy\n#\n- hosts: localhost\n  tasks:\n    - name: create Gateway Policy\n      vmware.ansible_for_nsxt.nsxt_policy_gateway_policy:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        id: test-gateway-policy\n        display_name: test-gateway-policy\n        state: \"present\"\n        domain_id: \"default\"\n        locked: True\n        rules:\n          - action: \"ALLOW\"\n            description: \"example-rule\"\n            sequence_number: 1\n            display_name: \"test-example-rule\"\n            id: \"test-example-rule\"\n            source_groups: [\"/infra/domains/vmc/groups/dbgroup\"]\n            destination_groups: [\"/infra/domains/vmc/groups/appgroup\"]\n            services: [\"/infra/services/HTTP\", \"/infra/services/CIM-HTTP\"]\n            tag: my-tag\n            tags:\n              - scope: scope-1\n                tag: tag-1\n            logged: True\n            notes: dummy-notes\n            ip_protocol: IPV4_IPV6\n            scope:\n              - /infra/tier-0s/PLR1\n            profiles: \"encryption algorithm\""
  },
  {
    "path": "tests/playbooks/policy/test_nsxt_policy_group.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to test Policy Group\n#\n- hosts: localhost\n  tasks:\n    - name: create Policy Group\n      vmware.ansible_for_nsxt.nsxt_policy_group:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        id: test-policy-group\n        display_name: test-policy-group\n        state: \"present\"\n        domain_id: \"default\"\n        expression:\n          - member_type: \"VirtualMachine\"\n            value: \"webvm\"\n            key: \"Tag\"\n            operator: \"EQUALS\"\n            resource_type: \"Condition\""
  },
  {
    "path": "tests/playbooks/policy/test_nsxt_policy_ip_block.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to test IP Block\n#\n- hosts: localhost\n  tasks:\n    - name: create IP Block\n      vmware.ansible_for_nsxt.nsxt_policy_ip_block:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        display_name: test-ip-blk\n        state: \"absent\"\n        cidr: \"192.168.0.0/16\""
  },
  {
    "path": "tests/playbooks/policy/test_nsxt_policy_ip_pool.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to test IP Pool\n#\n- hosts: localhost\n  tasks:\n    - name: create IP Pool\n      vmware.ansible_for_nsxt.nsxt_policy_ip_pool:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        display_name: test-ip-pool-1\n        state: \"present\"\n        tags:\n        - tag: \"a\"\n          scope: \"b\"\n        pool_block_subnets:\n          - id: test-ip-subnet-1\n            state: present\n            ip_block_id: \"test-ip-blk-1\"\n            size: 16\n          - display_name: test-ip-subnet-2\n            state: present\n            ip_block_id: \"test-ip-blk-1\"\n            size: 16\n          - display_name: test-ip-subnet-3\n            state: present\n            ip_block_id: \"test-ip-blk-1\"\n            size: 8\n        pool_static_subnets:\n          - id: test-ip-static-subnet-1\n            state: present\n            allocation_ranges:\n              - start: '192.116.0.10'\n                end: '192.116.0.20'\n              - start: '192.116.0.30'\n                end: '192.116.0.40'\n            cidr: '192.116.0.0/26'\n          - display_name: test-ip-static-subnet-2\n            state: present\n            allocation_ranges:\n              - start: '192.116.1.10'\n                end: '192.116.1.20'\n              - start: '192.116.1.30'\n                end: '192.116.1.40'\n            cidr: '192.116.1.0/26'"
  },
  {
    "path": "tests/playbooks/policy/test_nsxt_policy_l2_bridge_ep_profile.yml",
    "content": "# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to test L2 Bridge Endpoint Profile\n#\n- hosts: localhost\n  tasks:\n    - name: update L2 Bridge Endpoint Profile\n      vmware.ansible_for_nsxt.nsxt_policy_l2_bridge_ep_profile:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        display_name: test-br-profile\n        state: present\n        edge_nodes_info:\n          - edge_cluster_display_name: edge-cluster\n            edge_node_id: 60f7dc14-d11c-11ea-8fb5-000c29e1fb0e\n        failover_mode: NON_PREEMPTIVE\n"
  },
  {
    "path": "tests/playbooks/policy/test_nsxt_policy_security_policy.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to test Security Policy\n#\n- hosts: localhost\n  tasks:\n    - name: create Security Policy\n      vmware.ansible_for_nsxt.nsxt_policy_security_policy:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        id: test-sec-pol\n        display_name: test-sec-pol\n        state: \"present\"\n        domain_id: \"default\"\n        locked: True\n        rules:\n          - action: \"ALLOW\"\n            description: \"example-rule\"\n            sequence_number: 1\n            display_name: \"test-example-rule\"\n            id: \"test-example-rule\"\n            source_groups: [\"/infra/domains/vmc/groups/dbgroup\"]\n            destination_groups: [\"/infra/domains/vmc/groups/appgroup\"]\n            services: [\"/infra/services/HTTP\", \"/infra/services/CIM-HTTP\"]\n            tag: my-tag\n            tags:\n              - scope: scope-1\n                tag: tag-1\n            logged: True\n            notes: dummy-notes\n            ip_protocol: IPV4_IPV6\n            scope:\n              - /infra/tier-0s/PLR1\n            profiles: \"encryption algorithm\""
  },
  {
    "path": "tests/playbooks/policy/test_nsxt_policy_segment.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to test Segment\n#\n- hosts: localhost\n  tasks:\n    - name: Update Segment\n      vmware.ansible_for_nsxt.nsxt_policy_segment:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        state: present\n        domain_name: dn1\n        transport_zone_display_name: \"1-transportzone-730\"\n        replication_mode: \"SOURCE\"\n        address_bindings:\n          - ip_address: \"10.1.2.11\"\n        advanced_config:\n          address_pool_display_name: small-2-pool\n          connectivity: \"OFF\"\n          hybrid: False\n          local_egress: True\n        admin_state: UP\n        connectivity_path: \"/infra/tier-1s/d082bc25-a9b2-4d13-afe5-d3cecad4b854\"\n        subnets:\n          - gateway_address: \"40.1.1.1/16\"\n          # - dhcp_config:\n          #     # IPv4 example\n          #     options:\n          #       option121:\n          #         static_routes:\n          #           - network: \"10.22.12.2/23\"\n          #             next_hop: \"10.10.10.10\"\n          #     resource_type: SegmentDhcpV4Config\n          #     lease_time: 16400\n          #   gateway_address: \"192.40.10.1/24\"\n          #     # IPv6 Example\n          #     resource_type: SegmentDhcpV6Config\n          #     preferred_time: 2048\n          #     excluded_ranges:\n          #       - fc7e::1-fc7e::32\n          #     server_address: \"fc7e:f206:db42::2/48\"\n          #   gateway_address: \"fc7e:f206:db42::1/48\"\n        segment_ports:\n          - display_name: test-sp-1\n            state: present\n            tags:\n              - scope: \"scope-1\"\n                tag: \"tag-2\"\n            extra_configs:\n              - config_pair:\n                  key: key\n                  value: value\n            ignored_address_bindings:\n              - ip_address: \"10.1.2.122\"\n          - display_name: test-sp-2\n            state: present\n          - display_name: test-sp-3\n            state: present"
  },
  {
    "path": "tests/playbooks/policy/test_nsxt_policy_tier0.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to test Tier0\n#\n- hosts: localhost\n  tasks:\n    - name: Update Tier0\n      vmware.ansible_for_nsxt.nsxt_policy_tier0:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        display_name: test-tier0-1\n        state: present\n        ha_mode: \"ACTIVE_STANDBY\"\n        failover_mode: \"PREEMPTIVE\"\n        disable_firewall: True\n        force_whitelisting: True\n        rd_admin_field: \"122.34.12.124\"\n        tags:\n          - scope: \"a\"\n            tag: \"b\"\n        static_routes:\n          - state: present\n            display_name: test-sr\n            network: '12.12.12.0/24'\n            next_hops:\n              - ip_address: \"192.165.1.4\"\n        bfd_peers:\n          - state: present\n            display_name: test-peer-1\n            peer_address: \"192.100.100.5\"\n            bfd_profile_id: test-bfd-profile\n        locale_services:\n          - state: present\n            id: \"test-t0ls\"\n            route_redistribution_config:\n              redistribution_rules:\n                - name: abc\n                  route_redistribution_types: [\"TIER0_STATIC\", \"TIER0_NAT\"]\n            edge_cluster_info:\n              edge_cluster_id: \"7ef91a10-c780-4f48-a279-a5662db4ffa3\"\n            preferred_edge_nodes_info:\n              - edge_cluster_id: \"7ef91a10-c780-4f48-a279-a5662db4ffa3\"\n                edge_node_id: \"e10c42dc-db27-11e9-8cd0-000c291af7ee\"\n            ha_vip_configs:\n              - external_interface_info:\n                  - display_name: '3-policyconnectivity-64'\n                  - id: '4-policyconnectivity-562'\n                vip_subnets:\n                  - ip_addresses:\n                      - '12.12.12.12'\n                    prefix_len: 23\n            BGP:\n              state: present\n              local_as_num: '1211'\n              inter_sr_ibgp: False\n              graceful_restart_config:\n                mode: \"GR_AND_HELPER\"\n                timer:\n                  restart_timer: 12\n              route_aggregations:\n                - prefix: \"10.1.1.0/24\"\n                - prefix: \"11.1.0.0/24\"\n                  summary_only: False\n              neighbors:\n                - display_name: neigh1\n                  neighbor_address: \"1.2.3.4\"\n                  remote_as_num: \"12\"\n                  state: present\n            interfaces:\n              - id: \"test-t0-t0ls-iface\"\n                display_name: \"test-t0-t0ls-iface\"\n                state: present\n                subnets:\n                  - ip_addresses: [\"35.1.1.1\"]\n                    prefix_len: 24\n                segment_id: \"test-seg-4\"\n                edge_node_info:\n                  edge_cluster_id: \"7ef91a10-c780-4f48-a279-a5662db4ffa3\"\n                  edge_node_id: \"e10c42dc-db27-11e9-8cd0-000c291af7ee\"\n                mtu: 1500\n                urpf_mode: \"NONE\"\n                multicast:\n                  enabled: True\n                ipv6_ndra_profile_display_name: test\n        vrf_config:\n          display_name: my-vrf\n          id: my-vrf2\n          tier0_display_name: node-t0\n          tags:\n            - scope: scope-tag-1\n              tag: value-tag-1\n          route_distinguisher: 'ASN:4000'\n          evpn_transit_vni: 6000\n"
  },
  {
    "path": "tests/playbooks/policy/test_nsxt_policy_tier1.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to test Tier1\n#\n- hosts: localhost\n  tasks:\n    - name: Update Tier1\n      vmware.ansible_for_nsxt.nsxt_policy_tier1:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        display_name: test-tier22222\n        state: present\n        failover_mode: \"PREEMPTIVE\"\n        disable_firewall: True\n        force_whitelisting: True\n        enable_standby_relocation: False\n        tags:\n          - scope: \"a\"\n            tag: \"b\"\n        route_advertisement_rules:\n          - name: \"test-route-advertisement-rules\"\n            route_advertisement_types: ['TIER1_STATIC_ROUTES', 'TIER1_CONNECTED']\n            subnets: [\"35.1.1.1/23\"]\n        route_advertisement_types: ['TIER1_STATIC_ROUTES', 'TIER1_CONNECTED', 'TIER1_NAT']\n        tier0_display_name: \"node-t0\"\n        static_routes:\n          - state: present\n            display_name: test-sr\n            network: '12.12.12.0/24'\n            next_hops:\n              - ip_address: \"192.165.1.4\"\n        locale_services:\n          - state: present\n            display_name: test-t1ls-2\n            route_redistribution_config:\n              redistribution_rules:\n                - name: abc\n                  route_redistribution_types: [\"TIER0_STATIC\", \"TIER0_NAT\"]\n            ha_vip_configs:\n              - external_interface_info:\n                # Either of the two ways below can be used\n                - external_interface_path: /infra/tier-0s/pepsi/locale-services/1-policyconnectivity-706/interfaces/2-policyconnectivity-1411\n                - tier0_display_name: pepsi\n                  tier0_ls_display_name: 1-policyconnectivity-706\n                  tier0_ls_interface_display_name: 1-policyconnectivity-1649\n                vip_subnets:\n                  - ip_addresses:\n                      - '12.12.12.12'\n                    prefix_len: 23\n            interfaces:\n              - id: \"test-t1-t1ls-iface-2\"\n                display_name: \"test-t1-t1ls-iface\"\n                state: present\n                subnets:\n                  - ip_addresses: [\"35.1.1.1\"]\n                    prefix_len: 24\n                segment_id: \"test-seg-2\"\n                ipv6_ndra_profile_id: test\n                mtu: 1400\n                urpf_mode: NONE"
  },
  {
    "path": "tests/playbooks/policy/test_vm_tags.yaml",
    "content": "- hosts: localhost\n  tasks:\n    - name: Update Tags on VMs\n      vmware.ansible_for_nsxt.nsxt_vm_tags:\n        hostname: \"default\"\n        nsx_cert_path: /root/com.vmware.nsx.ncp/nsx.crt\n        nsx_key_path: /root/com.vmware.nsx.ncp/nsx.key\n        validate_certs: True\n        ca_path: /path/to/my/ca-bundle\n        virtual_machine_display_name: App-VM-1\n        remove_other_tags: False\n        add_tags:\n          - scope: \"my-scope\"\n            tag: \"my-tag\"\n          # - scope: \"my-scope1\"\n          #   tag: \"my-tag\"\n        remove_tags_with_scope:\n          - my-scope1"
  },
  {
    "path": "tests/playbooks/topologies/deploy_nsx_cluster/01_deploy_first_node.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to deploy the first NSX Appliance node. Also checks the node\n# status\n#\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - deploy_nsx_cluster_vars.yml\n  tasks:\n    - name: deploy NSX Manager OVA\n      vmware.ansible_for_nsxt.nsxt_deploy_ova:\n        ovftool_path: \"/usr/bin\"\n        datacenter: \"{{ nsx_node1['datacenter'] }}\"\n        datastore: \"{{ nsx_node1['datastore'] }}\"\n        portgroup: \"{{ nsx_node1['portgroup'] }}\"\n        cluster: \"{{ nsx_node1['cluster'] }}\"\n        vmname: \"{{ nsx_node1['hostname'] }}\"\n        hostname: \"{{ nsx_node1['hostname'] }}\"\n        dns_server: \"{{ dns_server }}\"\n        dns_domain: \"{{ domain }}\"\n        ntp_server: \"{{ ntp_server }}\"\n        gateway: \"{{ gateway }}\"\n        ip_address: \"{{ nsx_node1['mgmt_ip'] }}\"\n        netmask: \"{{ netmask }}\"\n        admin_password: \"{{ nsx_password }}\"\n        cli_password: \"{{ nsx_password }}\"\n        path_to_ova: \"{{ nsx_ova_path }}\"\n        ova_file: \"{{ nsx_ova }}\"\n        vcenter: \"{{ compute_managers[0]['mgmt_ip'] }}\"\n        vcenter_user: \"{{ compute_managers[0]['username'] }}\"\n        vcenter_passwd: \"{{ compute_managers[0]['password'] }}\"\n        deployment_size: \"small\"\n        # Note: The role below is for NSX 2.5 and above. For prior\n        # release, the role should be \"nsx-manager nsx-controller\"\n        role: \"NSX Manager\"\n\n    - name: Check manager status\n      vmware.ansible_for_nsxt.nsxt_manager_status:\n          hostname: \"{{ nsx_node1['mgmt_ip'] }}\"\n          username: \"{{ nsx_username }}\"\n          password: \"{{ nsx_password }}\"\n          validate_certs: \"{{ validate_certs }}\"\n          wait_time: 50\n"
  },
  {
    "path": "tests/playbooks/topologies/deploy_nsx_cluster/02_configure_compute_manager.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to register Compute Managers with NSX Appliance\n#\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - deploy_nsx_cluster_vars.yml\n  tasks:\n    - name: Register compute manager\n      vmware.ansible_for_nsxt.nsxt_fabric_compute_managers:\n          hostname: \"{{ nsx_node1.mgmt_ip }}\"\n          username: \"{{ nsx_username }}\"\n          password: \"{{ nsx_password }}\"\n          validate_certs: \"{{ validate_certs }}\"\n          display_name: \"{{ item.display_name }}\"\n          server: \"{{ item.mgmt_ip }}\"\n          origin_type: \"{{ item.origin_type }}\"\n          credential:\n            credential_type: \"{{ item.credential_type }}\"\n            username: \"{{ item.username }}\"\n            password: \"{{ item.password }}\"\n          state: present\n      with_items:\n        - \"{{compute_managers}}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/deploy_nsx_cluster/03_deploy_second_third_node.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Deploys remaining NSX appliance nodes and forms a cluster. Requires the first\n# NSX appliance node to be deployed and at least one Compute Manager registered.\n#\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - deploy_nsx_cluster_vars.yml\n  tasks:\n    - name: Deploying additional nodes\n      vmware.ansible_for_nsxt.nsxt_manager_auto_deployment:\n          hostname: \"{{ nsx_node1.mgmt_ip }}\"\n          username: \"{{ nsx_username }}\"\n          password: \"{{ nsx_password }}\"\n          validate_certs: \"{{ validate_certs }}\"\n          deployment_requests:\n          - roles:\n            - CONTROLLER\n            - MANAGER\n            form_factor: \"SMALL\"\n            user_settings:\n              cli_password: \"{{ nsx_password }}\"\n              root_password: \"{{ nsx_password }}\"\n            deployment_config:\n              placement_type: VsphereClusterNodeVMDeploymentConfig\n              vc_name: \"{{ compute_managers[0]['display_name'] }}\"\n              vc_username: \"{{ compute_managers[0]['username'] }}\"\n              vc_password: \"{{ compute_managers[0]['password'] }}\"\n              management_network: \"{{ item.portgroup }}\"\n              hostname: \"{{ item.hostname }}\"\n              compute: \"{{ item.cluster }}\"\n              storage: \"{{ item.datastore }}\"\n              default_gateway_addresses:\n              - \"{{ gateway }}\"\n              dns_servers:\n              - \"{{ dns_server }}\"\n              ntp_servers:\n              - \"{{ ntp_server }}\"\n              management_port_subnets:\n              - ip_addresses:\n                - \"{{ item.mgmt_ip }}\"\n                prefix_length: \"{{ item.prefix }}\"\n          state: present\n      with_items:\n        - \"{{ additional_nodes }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/deploy_nsx_cluster/04_add_nsx_license.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n#\n# Playbook to register Compute Managers with NSX Appliance\n#\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - deploy_nsx_cluster_vars.yml\n  tasks:\n    - name: Add NSX License\n      vmware.ansible_for_nsxt.nsxt_licenses:\n          hostname: \"{{ nsx_node1.mgmt_ip }}\"\n          username: \"{{ nsx_username }}\"\n          password: \"{{ nsx_password }}\"\n          validate_certs: \"{{ validate_certs }}\"\n          license_key: \"{{ item.license_key }}\"\n          state: \"{{ state }}\"\n      with_items:\n        - \"{{nsxt_licenses}}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/deploy_nsx_cluster/README.md",
    "content": "# Deploy NSX-T Cluster\n\n# Overview\nThe set of playbooks in this example deploy a full NSX Cluster. The playbooks\nare divided based on the workflow.\n\nThere are 3 main playbooks and a common variable files:\n\n* 01_deploy_first_node.yml\n* 02_configure_compute_manager.yml\n* 03_deploy_second_third_node.yml\n* deploy_nsx_cluster_vars.yml\n\nTo run the example, copy all the files two-levels up, edit the variables file\nto match your needs and run the playbooks in the order listed.\n\nValidated against:\n* NSX-T 2.4 GA\n* NSX-T 2.5 GA\n\nIt currently does not configure a cluster Virtual IP\n"
  },
  {
    "path": "tests/playbooks/topologies/deploy_nsx_cluster/deploy_nsx_cluster_vars.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# Variables file for deploying NSX-T Cluster\n#\n{\n\n  #\n  # Common NSX Appliance variables\n  #\n  \"nsx_username\": \"admin\",\n  \"nsx_password\": \"myPassword1!myPassword1!\",\n  \"validate_certs\": False,\n  \"state\": \"present\",\n\n  #\n  # OVA/OVF Information. Path can be on local file system or a HTTP URL\n  #\n  \"nsx_ova_path\": \"/media/disk2\",\n#  \"nsx_ova\": \"nsx-unified-appliance-3.0.0.0.0.15946739.ova\",\n  \"nsx_ova\": \"nsx-unified-appliance-3.0.1.0.0.16404476.ova\",\n\n  #\n  # Common network details. This assumes all NSX appliance nodes are on the\n  # same subnet. If there is a need to deploy NSX appliance nodes which are\n  # on different subnets, add node specific details in the blocks below and\n  # use them in the playbooks instead.\n  #\n  \"domain\": \"mylab.local\",\n  \"netmask\": \"255.255.255.224\",\n  \"gateway\": \"10.114.200.33\",\n  \"dns_server\": \"10.116.1.201\",\n  \"ntp_server\": \"10.114.200.8\",\n\n  #\n  # First NSX appliance node. Defined separate based on the consumption.\n  # Accepts both IP (IPv4) and FQDN for 'mgmt_ip'\n  #\n  \"nsx_node1\": {\n    \"hostname\": \"mynsx-01.mylab.local\",\n    \"mgmt_ip\": \"10.114.200.41\",\n    \"datacenter\": \"Datacenter\",\n    \"cluster\": \"Management\",\n    \"datastore\": \"datastore36\",\n    \"portgroup\": \"VM Network\"\n  },\n\n  #\n  # Additional nodes defined as an array so that its easier to iterate\n  # through them in the playbook.\n  #\n  \"additional_nodes\": [\n    {\n      \"hostname\": \"mynsx-02.mylab.local\",\n      \"mgmt_ip\": \"10.114.200.42\",\n      \"prefix\": \"27\",\n      \"datacenter\": \"Datacenter\",\n      \"cluster\": \"Management\",\n      \"datastore\": \"datastore36\",\n      \"portgroup\": \"VM Network\"\n    },\n    {\n      \"hostname\": \"mynsx-03.mylab.local\",\n      \"mgmt_ip\": \"10.114.200.43\",\n      \"prefix\": \"27\",\n      \"datacenter\": \"Datacenter\",\n      \"cluster\": \"Management\",\n      \"datastore\": \"datastore36\",\n      \"portgroup\": \"VM Network\"\n    }\n  ],\n\n  #\n  # One or more compute managers that have to be registered with NSX\n  #\n  \"compute_managers\": [\n    {\n      \"display_name\": \"vcenter\",\n      \"mgmt_ip\": \"10.114.200.6\",\n      \"origin_type\": \"vCenter\",\n      \"credential_type\": \"UsernamePasswordLoginCredential\",\n      \"username\": \"administrator@madhu.local\",\n      \"password\": \"VMware1!\"\n    }\n  ],\n\n  #\n  # NSX-T licenses\n  #\n  \"nsxt_licenses\": [\n    {\n      \"license_key\": \"XXXXX-XXXXX-XXXXX-XXXXX-XXXXX\"\n    }\n  ],\n}\n"
  },
  {
    "path": "tests/playbooks/topologies/misc/create_and_attach_t0_t1_routers.yml",
    "content": "# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n\n#\n# This example shows how to create T0 and T1 Router and connect them\n#\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars:\n    nsx: \"192.168.200.11\"\n    user: \"admin\"\n    password: \"myPassword1!myPassword1!\"\n    state: \"present\"\n  \n  tasks:\n    - name: Create T0\n      vmware.ansible_for_nsxt.nsxt_logical_routers:\n        hostname: \"{{ nsx }}\"\n        username: \"{{ user }}\"\n        password: \"{{ password }}\"\n        validate_certs: False\n        state: \"{{ state }}\"\n        display_name: \"myTier-0\"\n        edge_cluster_name: \"Edge-Cluster-01\"\n        router_type: \"TIER0\"\n        high_availability_mode: \"ACTIVE_ACTIVE\"\n\n    - name: Create T1\n      vmware.ansible_for_nsxt.nsxt_logical_routers:\n        hostname: \"{{ nsx }}\"\n        username: \"{{ user }}\"\n        password: \"{{ password }}\"\n        validate_certs: False\n        state: \"{{ state }}\"\n        display_name: \"myTier-1\"\n        edge_cluster_name: \"Edge-Cluster-01\"\n        router_type: \"TIER1\"\n\n    - name: Create Tier0 router port to Tier1\n      vmware.ansible_for_nsxt.nsxt_logical_router_ports:\n        hostname: \"{{ nsx }}\"\n        username: \"{{ user }}\"\n        password: \"{{ password }}\"\n        validate_certs: False\n        state: \"{{ state }}\"\n        display_name: \"RouterPortOnTier0toT1\"\n        resource_type: \"LogicalRouterLinkPortOnTIER0\"\n        logical_router_name: \"myTier-0\"\n\n    - name: Get Router ID\n      uri:\n        url: \"https://192.168.200.11/api/v1/logical-router-ports?resource_type=LogicalRouterLinkPortOnTIER0\"\n        user: \"{{ user }}\"\n        password: \"{{ password }}\"\n        validate_certs: False\n        return_content: yes\n        use_proxy: false\n        force_basic_auth: true\n      register: ports\n\n    - name: Create Tier1 router port to Tier0\n      vmware.ansible_for_nsxt.nsxt_logical_router_ports:\n        hostname: \"{{ nsx }}\"\n        username: \"{{ user }}\"\n        password: \"{{ password }}\"\n        validate_certs: False\n        state: \"{{ state }}\"\n        display_name: \"RouterPortOnTier1toT0\"\n        resource_type: \"LogicalRouterLinkPortOnTIER1\"\n        logical_router_name: \"myTier-1\"\n        linked_logical_router_port_id:\n          target_id: \"{{ ports.json['results'][0].id }}\"\n          target_type: LogicalPort\n\n\n"
  },
  {
    "path": "tests/playbooks/topologies/policy_modules/01_create_t0_gateway.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: localhost\n  become: yes\n  vars_files:\n    - build_topology_vars.yml\n  tasks:\n    - name: Modify Tier0\n      vmware.ansible_for_nsxt.nsxt_policy_tier0:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        state: \"{{ state }}\"\n        display_name: \"{{ item.display_name }}\"\n        ha_mode: \"{{ item.ha_mode }}\"\n        tags: \"{{ item.tags }}\"\n        locale_services: \"{{ item.locale_services }}\"\n      with_items:\n        - \"{{ tier0_gateways }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/policy_modules/02_create_t1_gateway.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: localhost\n  become: yes\n  vars_files:\n    - build_topology_vars.yml\n  tasks:\n    - name: Modify Tier1\n      vmware.ansible_for_nsxt.nsxt_policy_tier1:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        state: \"{{ state }}\"\n        display_name: \"{{ item.display_name }}\"\n        tier0_display_name: \"{{ item.tier0_display_name }}\"\n        tags: \"{{ item.tags }}\"\n      with_items:\n        - \"{{ tier1_gateways }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/policy_modules/03_create_segments.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: localhost\n  become: yes\n  vars_files:\n    - build_topology_vars.yml\n  tasks:\n    - name: Modify Segment\n      vmware.ansible_for_nsxt.nsxt_policy_segment:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        state: \"{{ state }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        display_name: \"{{ item.display_name }}\"\n        tier1_id: \"{{ item.tier1_display_name }}\"\n        domain_name: \"{{ item.domain_name }}\"\n        transport_zone_display_name: \"{{ item.tz }}\"\n        subnets: \"{{ item.subnets }}\"\n        tags: \"{{ item.tags }}\"\n      with_items:\n        - \"{{ segments }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/policy_modules/04_create_groups.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: localhost\n  become: yes\n  vars_files:\n    - build_topology_vars.yml\n  tasks:\n    - name: Modify Groups\n      vmware.ansible_for_nsxt.nsxt_policy_group:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        state: \"{{ state }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        domain_id: \"{{ item.domain_id }}\"\n        display_name: \"{{ item.display_name }}\"\n        expression: \"{{ item.expression }}\"\n        tags: \"{{ item.tags }}\"\n      with_items:\n        - \"{{ mygroups }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/policy_modules/05_create_security_policy.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: localhost\n  become: yes\n  vars_files:\n    - build_topology_vars.yml\n  tasks:\n    - name: Modify Security Policy\n      vmware.ansible_for_nsxt.nsxt_policy_security_policy:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        state: \"{{ state }}\"\n        display_name: \"{{ item.display_name }}\"\n        domain_id: \"{{ item.domain_id }}\"\n        category: \"{{ item.category }}\"\n        rules: \"{{ item.rules }}\"\n        tags: \"{{ item.tags }}\"\n      with_items:\n        - \"{{ security_policies }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/policy_modules/README.md",
    "content": "Example to build the following Topology:\n\n* 1 Tier0 Gateway\n* 1 Tier1 Gateway\n* 3 Subnets\n* 3 Groups\n* 3 Security Policies with 1 rule each\n"
  },
  {
    "path": "tests/playbooks/topologies/policy_modules/build_topology.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- import_playbook: 01_create_t0_gateway.yml\n- import_playbook: 02_create_t1_gateway.yml\n- import_playbook: 03_create_segments.yml\n- import_playbook: 04_create_groups.yml\n- import_playbook: 05_create_security_policy.yml\n"
  },
  {
    "path": "tests/playbooks/topologies/policy_modules/build_topology_vars.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# Variables file to deploy a simple topology\n\n{\n    \"nsx_manager\": \"nsx_manager_IP\",\n    \"nsx_username\": \"nsx_username\",\n    \"nsx_password\": \"nsx_password\",\n    \"validate_certs\": \"false\",\n\n    \"state\": \"present\",\n\n    \"tier0_gateways\": [\n      {\n        \"display_name\": \"Tier-0\",\n        \"ha_mode\": \"ACTIVE_STANDBY\",\n        \"tags\": [\n          {\n            \"tag\": \"ansible\",\n            \"scope\": \"demo\"\n          }\n        ],\n        \"locale_services\": [\n          {\n            \"state\": \"present\",\n            \"id\": \"test-t0ls\",\n            \"route_redistribution_config\": {\n              \"redistribution_rules\": [\n                \"route_redistribution_types\": [\"TIER0_STATIC\", \"TIER0_NAT\"]\n              ]\n            },\n            \"edge_cluster_info\": {\n              \"edge_cluster_display_name\": \"Edge-Cluster-01\",\n            },\n            \"preferred_edge_nodes_info\": [\n              {\n                \"edge_cluster_display_name\": \"Edge-Cluster-01\",\n                \"edge_node_display_name\": \"EdgeNode-01\"\n              }\n            ],\n            \"BGP\": {\n              \"state\": \"present\",\n              \"local_as_num\": '1211'\n            }\n          }\n        ]\n      }\n    ],\n\n    \"tier1_gateways\": [\n      {\n        \"display_name\": \"Tier-1\",\n        \"tier0_display_name\": \"Tier-0\",\n        \"tags\": [\n          {\n            \"tag\": \"ansible\",\n            \"scope\": \"demo\"\n          }\n        ]\n      }\n    ],\n\n    \"segments\": [\n        {\n            \"display_name\": \"Web-Segment\",\n            \"tier1_display_name\": \"Tier-1\",\n            \"tz\": \"Overlay-TZ\",\n            \"domain_name\": \"mylab.net\",\n            \"subnets\": [\n                {\n                  \"gateway_address\": \"192.168.10.1/24\"\n                }\n            ],\n            \"tags\": [\n                {\n                  \"tag\": \"ansible\",\n                  \"scope\": \"demo\"\n                },\n                {\n                  \"tag\": \"web\",\n                  \"scope\": \"east\"\n                }\n            ]\n        },\n        {\n            \"display_name\": \"App-Segment\",\n            \"tier1_display_name\": \"Tier-1\",\n            \"tz\": \"Overlay-TZ\",\n            \"domain_name\": \"mylab.net\",\n            \"subnets\": [\n                {\n                  \"gateway_address\": \"192.168.20.1/24\"\n                }\n            ],\n            \"tags\": [\n                {\n                  \"tag\": \"ansible\",\n                  \"scope\": \"demo\"\n                },\n                {\n                  \"tag\": \"app\",\n                  \"scope\": \"east\"\n                }\n            ]\n        },\n        {\n            \"display_name\": \"DB-Segment\",\n            \"tier1_display_name\": \"Tier-1\",\n            \"tz\": \"Overlay-TZ\",\n            \"domain_name\": \"mylab.net\",\n            \"subnets\": [\n                {\n                  \"gateway_address\": \"192.168.30.1/24\"\n                }\n            ],\n            \"tags\": [\n                {\n                  \"tag\": \"ansible\",\n                  \"scope\": \"demo\"\n                },\n                {\n                  \"tag\": \"db\",\n                  \"scope\": \"east\"\n                }\n            ]\n        }\n    ],\n\n# Note: 'group' is a reserved key. Cant use it here.\n    \"mygroups\": [\n        {\n            \"display_name\": \"web-VMs\",\n            \"domain_id\": \"default\",\n            \"expression\": [\n                {\n                    \"member_type\": \"VirtualMachine\",\n                    \"value\": \"web\",\n                    \"key\": \"Tag\",\n                    \"operator\": \"EQUALS\",\n                    \"resource_type\": \"Condition\"\n                }\n            ],\n            \"tags\": [\n                {\n                  \"tag\": \"ansible\",\n                  \"scope\": \"demo\"\n                },\n                {\n                  \"tag\": \"web\",\n                  \"scope\": \"east\"\n                }\n            ]\n        },\n        {\n            \"display_name\": \"app-VMs\",\n            \"domain_id\": \"default\",\n            \"expression\": [\n                {\n                    \"member_type\": \"VirtualMachine\",\n                    \"value\": \"app\",\n                    \"key\": \"Tag\",\n                    \"operator\": \"EQUALS\",\n                    \"resource_type\": \"Condition\"\n                }\n            ],\n            \"tags\": [\n                {\n                  \"tag\": \"ansible\",\n                  \"scope\": \"demo\"\n                },\n                {\n                  \"tag\": \"app\",\n                  \"scope\": \"east\"\n                }\n            ]\n        },\n        {\n            \"display_name\": \"db-VMs\",\n            \"domain_id\": \"default\",\n            \"expression\": [\n                {\n                    \"member_type\": \"VirtualMachine\",\n                    \"value\": \"web\",\n                    \"key\": \"Tag\",\n                    \"operator\": \"EQUALS\",\n                    \"resource_type\": \"Condition\"\n                }\n            ],\n            \"tags\": [\n                {\n                  \"tag\": \"ansible\",\n                  \"scope\": \"demo\"\n                },\n                {\n                  \"tag\": \"db\",\n                  \"scope\": \"east\"\n                }\n            ]\n        }\n    ],\n\n    \"security_policies\" : [\n        {\n            \"display_name\": \"web-to-app\",\n            \"domain_id\": \"default\",\n            \"category\": \"Application\",\n            \"rules\": [\n                {\n                    \"display_name\": \"app-port\",\n                    \"description\": \"Rule for Application port\",\n                    \"sequence_number\": 1,\n                    \"source_groups\": [\n                            \"/infra/domains/default/groups/web-VMs\"\n                        ],\n                    \"destination_groups\": [\n                            \"/infra/domains/default/groups/app-VMs\"\n                        ],\n                    \"services\": [\n                            \"/infra/services/AD_Server\"\n                        ],\n                    \"action\": \"ALLOW\"\n                },\n                {\n                    \"display_name\": \"Catch-All\",\n                    \"description\": \"Catch All rule\",\n                    \"sequence_number\": 2,\n                    \"source_groups\": [\n                            \"any\"\n                        ],\n                    \"destination_groups\": [\n                            \"any\"\n                        ],\n                    \"services\": [\n                            \"any\"\n                        ],\n                    \"action\": \"DROP\"\n                },\n            ],\n            \"tags\": [\n                {\n                    \"tag\": \"ansible\",\n                    \"scope\": \"demo\"\n                }\n            ]\n        },\n        {\n            \"display_name\": \"db\",\n            \"domain_id\": \"default\",\n            \"category\": \"Infrastructure\",\n            \"rules\": [\n                {\n                    \"display_name\": \"MySQL\",\n                    \"description\": \"Rule for Application port\",\n                    \"sequence_number\": 1,\n                    \"source_groups\": [\n                            \"any\"\n                        ],\n                    \"destination_groups\": [\n                            \"any\"\n                        ],\n                    \"services\": [\n                            \"/infra/services/MySQL\"\n                        ],\n                    \"action\": \"ALLOW\"\n                },\n                {\n                    \"display_name\": \"Catch-All\",\n                    \"description\": \"Catch All rule\",\n                    \"sequence_number\": 2,\n                    \"source_groups\": [\n                            \"any\"\n                        ],\n                    \"destination_groups\": [\n                            \"any\"\n                        ],\n                    \"services\": [\n                            \"any\"\n                        ],\n                    \"action\": \"DROP\"\n                },\n            ],\n            \"tags\": [\n                {\n                    \"tag\": \"ansible\",\n                    \"scope\": \"demo\"\n                }\n            ]\n        }\n    ]\n}\n"
  },
  {
    "path": "tests/playbooks/topologies/policy_modules/cleanup_topology.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- import_playbook: 05_create_security_policy.yml\n- import_playbook: 04_create_groups.yml\n- import_playbook: 03_create_segments.yml\n- import_playbook: 02_create_t1_gateway.yml\n- import_playbook: 01_create_t0_gateway.yml\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/01_setup_transport_zones.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - setup_infra_vars.yml\n  tasks:\n    - name: Create transport zone\n      vmware.ansible_for_nsxt.nsxt_transport_zones:\n        hostname: \"{{ nsx_node1.mgmt_ip }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        resource_type: \"TransportZone\"\n        display_name: \"{{ item.display_name }}\"\n        description: \"{{ item.description }}\"\n        transport_type: \"{{ item.transport_type }}\"\n        host_switch_name: \"{{ item.host_switch_name }}\"\n        state: \"{{ state }}\"\n      with_items:\n        - \"{{ transport_zones }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/01_setup_transport_zones_9x.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - setup_infra_vars_9x.yml\n  tasks:\n    - name: Create transport zone\n      vmware.ansible_for_nsxt.nsxt_transport_zones:\n        hostname: \"{{ nsx_node1.mgmt_ip }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        resource_type: \"TransportZone\"\n        display_name: \"{{ item.display_name }}\"\n        description: \"{{ item.description }}\"\n        tz_type: \"{{item.tz_type}}\"\n        state: \"{{ state }}\"\n      with_items:\n        - \"{{ transport_zones }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/02_setup_TEP_IP_Pools.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - setup_infra_vars.yml\n  tasks:\n    - name: Create IP Pools\n      vmware.ansible_for_nsxt.nsxt_policy_ip_pool:\n        hostname: \"{{ nsx_node1.mgmt_ip }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        display_name: \"{{ item.display_name }}\"\n        pool_static_subnets: \"{{ item.pool_static_subnets }}\"\n        state: \"{{ state }}\"\n      with_items:\n        - \"{{ ip_pools  }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/03_setup_transport_node_profiles.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - setup_infra_vars.yml\n  tasks:\n    - name: Create Transport Node Profiles\n      vmware.ansible_for_nsxt.nsxt_transport_node_profiles:\n        hostname: \"{{ nsx_node1.mgmt_ip }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        resource_type: TransportNodeProfile\n        display_name: \"{{ item.display_name }}\"\n        description: \"{{ item.description }}\"\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{ item.host_switches }}\"\n        transport_zone_endpoints: \"{{ item.transport_zone_endpoints }}\"\n        state: \"{{ state }}\"\n      with_items:\n        - \"{{ transport_node_profiles }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/03_setup_transport_node_profiles_9x.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - setup_infra_vars_9x.yml\n  tasks:\n    - name: Create Transport Node Profiles\n      vmware.ansible_for_nsxt.nsxt_transport_node_profiles:\n        hostname: \"{{ nsx_node1.mgmt_ip }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        resource_type: TransportNodeProfile\n        display_name: \"{{ item.display_name }}\"\n        description: \"{{ item.description }}\"\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{ item.host_switches }}\"\n        state: \"{{ state }}\"\n      with_items:\n        - \"{{ transport_node_profiles }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/04_setup_transport_nodes.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - setup_infra_vars.yml\n  tasks:\n    - name: Create Transport Nodes\n      vmware.ansible_for_nsxt.nsxt_transport_nodes:\n        hostname: \"{{ nsx_node1.mgmt_ip }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        display_name: \"{{ item.display_name }}\"\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{ item.host_switches }}\"\n        transport_zone_endpoints: \"{{ item.transport_zone_endpoints }}\"\n        node_deployment_info: \"{{ item.node_deployment_info }}\"\n        state: \"{{ state }}\"\n      with_items:\n        - \"{{ transport_nodes }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/04_setup_transport_nodes_9x.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - setup_infra_vars_9x.yml\n  tasks:\n    - name: Create Transport Nodes\n      vmware.ansible_for_nsxt.nsxt_transport_nodes:\n        hostname: \"{{ nsx_node1.mgmt_ip }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        display_name: \"{{ item.display_name }}\"\n        host_switch_spec:\n          resource_type: StandardHostSwitchSpec\n          host_switches: \"{{ item.host_switches }}\"\n        node_deployment_info: \"{{ item.node_deployment_info }}\"\n        state: \"{{ state }}\"\n      with_items:\n        - \"{{ transport_nodes }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/05_setup_edge_cluster.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - setup_infra_vars.yml\n  tasks:\n    - name: Add edge cluster\n      vmware.ansible_for_nsxt.nsxt_edge_clusters:\n        hostname: \"{{ nsx_node1.mgmt_ip }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        display_name: \"{{ item.display_name }}\"\n        cluster_profile_bindings: \"{{ item.cluster_profile_bindings }}\"\n        members: \"{{ item.members }}\"\n        state: \"{{ state }}\"\n      with_items:\n        - \"{{ edge_clusters }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/06_setup_transport_node_collections.yml",
    "content": "# Copyright 2020 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n---\n- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - setup_infra_vars.yml\n  tasks:\n    - name: Create Transport Node Collections\n      vmware.ansible_for_nsxt.nsxt_transport_node_collections:\n        hostname: \"{{ nsx_node1.mgmt_ip }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        display_name: \"{{ item.display_name }}\"\n        description: \"{{ item.description }}\"\n        resource_type: \"TransportNodeCollection\"\n        compute_manager_name: \"{{ item.compute_manager_name }}\"\n        cluster_name: \"{{ item.cluster_name }}\"\n        transport_node_profile_name: \"{{ item.transport_node_profile_name }}\"\n        state: \"{{ state }}\"\n      with_items:\n        - \"{{ transport_node_collections }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/README.md",
    "content": "# Setup Day-1 Infra\n\n# Overview\nThe set of playbooks in this example deploy all the Day-1 Infra objects needed\nto start using NSX-T. The playbooks are divided based on the workflow.\n\nThere are 4 main playbooks and a common variable file:\n\n* 01_setup_transport_zones.yml\n* 02_setup_TEP_IP_Pools.yml: In this example, a single IP Pool is used to provide TEP IP for both Edge and Host Transport nodes.\n* 03_setup_transport_node_profiles.yml\n* 04_setup_transport_nodes.yml: Creates both Edge and Host Transport nodes\n* 05_setup_edge_cluster.yml\n* setup_infra_vars.yml: The variables file\n\nTo delete all objects, change the 'state' to 'absent' in the variables file and run the playbooks in the reverse order:\n\n* 05_setup_edge_cluster.yml\n* 04_setup_transport_nodes.yml\n* 03_setup_transport_node_profiles.yml\n* 02_setup_TEP_IP_Pools.yml\n* 01_setup_transport_zone.yml\n\nValidated against:\n* NSX-T 2.4 GA\n* NSX-T 2.5 GA\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/setup_infra_vars.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n#\n# Variables file for Day-0/1 setup\n# Creates the following:\n#   - 2 Transport Zones\n#   - 1 IP Pool (used by Edge)\n#   - 1 Transport Node Profile with 2 TZ endpoints\n#   - 2 Edge Transport Nodes\n#   - 2 ESX Host Transport Nodes\n#   - 1 Edge Cluster with the 2 Edge Nodes\n#\n{\n\n  #\n  # Flag to create or delete all the objects\n  # Accepts: 'present' to create; 'absent' to delete\n  #\n  \"state\": \"present\",\n\n  #\n  # Common NSX Appliance variables\n  #\n  \"nsx_username\": \"admin\",\n  \"nsx_password\": \"myPassword1!myPassword1!\",\n  \"validate_certs\": False,\n\n  #\n  # First NSX appliance node. Defined separate based on the consumption.\n  # Accepts both IP (IPv4) and FQDN for 'mgmt_ip'\n  #\n  \"nsx_node1\": {\n    \"hostname\": \"mynsx-01.mylab.local\",\n    \"mgmt_ip\": \"10.114.200.41\",\n    \"datacenter\": \"Datacenter\",\n    \"cluster\": \"Management\",\n    \"datastore\": \"datastore36\",\n    \"portgroup\": \"VM Network\"\n  },\n\n  \"transport_zones\": [\n    {\n      \"display_name\": \"Overlay-TZ\",\n      \"description\": \"NSX Configured Overlay Transport Zone\",\n      \"transport_type\": \"OVERLAY\",\n      \"host_switch_name\": \"nvds\"\n    },\n    {\n      \"display_name\": \"VLAN-TZ\",\n      \"description\": \"NSX Configured VLAN Transport Zone\",\n      \"transport_type\": \"VLAN\",\n      \"host_switch_name\": \"nvds\"\n    }\n  ],\n\n  \"ip_pools\": [\n    {\n      \"display_name\": \"to-del-TEP-IP-Pool\",\n      \"pool_static_subnets\": [\n        {\n          \"display_name\": \"TEP_ip_pool_subnet\",\n          \"state\": \"present\",\n          \"allocation_ranges\": [\n            {\n              \"start\": \"172.16.227.50\",\n              \"end\": \"172.16.227.59\"\n            }\n          ],\n          \"gateway_ip\": \"172.16.227.1\",\n          \"cidr\": \"172.16.227.0/24\"\n        }\n      ]\n    }\n  ],\n\n  \"transport_node_profiles\": [\n    {\n      \"display_name\": \"TNP-1\",\n      \"description\": \"Compute Transport Node Profile\",\n      \"host_switches\": [\n        {\n\n          \"host_switch_name\": \"vds7\",\n          \"host_switch_id\": \"50 35 17 4a 3d be 59 37-57 d0 0d 03 11 ae 7e a2\",\n          \"host_switch_type\": \"VDS\",\n          \"host_switch_mode\": \"STANDARD\",\n          \"host_switch_profiles\": [\n            {\n              \"name\": \"nsx-default-uplink-hostswitch-profile\",\n              \"type\": \"UplinkHostSwitchProfile\"\n            }\n          ],\n          \"pnics\": [],\n          \"uplinks\": [\n            {\n              \"vds_uplink_name\": \"uplink1\",\n              \"uplink_name\": \"uplink-1\"\n            },\n            {\n              \"vds_uplink_name\": \"uplink2\",\n              \"uplink_name\": \"uplink-2\"\n            }\n          ],\n          \"ip_assignment_spec\": {\n              \"resource_type\": \"StaticIpPoolSpec\",\n              \"ip_pool_name\": \"TEP-IP-Pool\"\n          },\n          \"transport_zone_endpoints\": [\n            {\n              \"transport_zone_name\": \"Overlay-TZ\"\n            }\n          ]\n        }\n      ],\n      \"transport_zone_endpoints\": []\n    }\n  ],\n\n\n  \"transport_node_collections\": [\n    {\n      \"state\": \"present\",\n      \"display_name\": \"workload-cluster-1-collection\",\n      \"description\": \"TNP for cluster1\",\n      \"resource_type\": \"TransportNodeCollection\",\n      \"compute_manager_name\": \"vcenter7\",\n      \"cluster_name\": \"workload-cluster1\",\n      \"transport_node_profile_name\": \"TNP-1\"\n    }\n  ],\n\n\n  \"transport_nodes\": [\n    {\n      \"display_name\": \"EdgeNode-01\",\n      \"description\": \"NSX Edge Node 01\",\n      \"host_switches\": [\n        {\n          \"host_switch_name\": \"nvds\",\n          \"host_switch_type\": \"NVDS\",\n          \"host_switch_mode\": \"STANDARD\",\n          \"host_switch_profiles\": [\n            {\n              \"name\": \"nsx-edge-single-nic-uplink-profile\",\n              \"type\": \"UplinkHostSwitchProfile\"\n            }\n          ],\n          \"pnics\": [\n            {\n              \"device_name\": \"fp-eth0\",\n              \"uplink_name\": \"uplink-1\"\n            }\n          ],\n          \"ip_assignment_spec\":\n            {\n              \"resource_type\": \"StaticIpPoolSpec\",\n              \"ip_pool_name\": \"TEP-IP-Pool\"\n            },\n          \"transport_zone_endpoints\": [\n            {\n              \"transport_zone_name\": \"Overlay-TZ\"\n            }\n          ]\n        }\n      ],\n      \"transport_zone_endpoints\": [],\n      \"node_deployment_info\": {\n        \"deployment_type\": \"VIRTUAL_MACHINE\",\n        \"deployment_config\": {\n          \"form_factor\": \"SMALL\",\n          \"vm_deployment_config\": {\n            \"vc_name\": \"vcenter\",\n            \"vc_username\": \"administrator@madhu.local\",\n            \"vc_password\": \"VMware1!\",\n            \"storage\": \"datastore7\",\n            \"compute\": \"Management\",\n            \"host\": \"10.114.200.7\",\n            \"data_networks\": [\n              \"VM Network\",\n              \"lab-dvpg\",\n              \"lab-dvpg\"\n            ],\n            \"default_gateway_addresses\": [ \"10.114.200.1\" ],\n            \"management_network\": \"VM Network\",\n            \"management_port_subnets\": [\n              {\n                \"ip_addresses\": [ \"10.114.200.14\" ],\n                \"prefix_length\": 27\n              }\n            ],\n            \"placement_type\": \"VsphereDeploymentConfig\"\n          },\n          \"node_user_settings\": {\n            \"cli_username\": \"admin\" ,\n            \"root_password\": \"myPassword1!myPassword1!\",\n            \"cli_password\": \"myPassword1!myPassword1!\",\n            \"audit_username\": \"audit\",\n            \"audit_password\": \"myPassword1!myPassword1!\"\n          }\n        },\n        \"node_settings\": {\n          \"allow_ssh_root_login\": \"True\",\n          \"enable_ssh\": \"True\",\n          \"hostname\": \"edgenode-01.madhu.local\"\n        },\n        \"resource_type\": \"EdgeNode\",\n        \"display_name\": \"EdgeNode-01\"\n      }\n    },\n    {\n      \"resource_type\": \"TransportNode\",\n      \"display_name\": \"esx7-12\",\n      \"description\": \"Host Transport Node for ESXi7-12\",\n      \"host_switches\": [\n        {\n          \"host_switch_name\": \"nsxvswitch\",\n          \"host_switch_type\": \"NVDS\",\n          \"host_switch_mode\": \"STANDARD\",\n          \"host_switch_profiles\": [\n            {\n              \"name\": \"nsx-default-uplink-hostswitch-profile\",\n              \"type\": \"UplinkHostSwitchProfile\"\n            }\n          ],\n          \"pnics\": [\n            {\n              \"device_name\": \"vmnic1\",\n              \"uplink_name\": \"uplink-1\"\n            }\n          ],\n          \"ip_assignment_spec\": {\n            \"resource_type\": \"StaticIpPoolSpec\",\n            \"ip_pool_name\": \"TEP-IP-Pool\"\n          },\n          \"transport_zone_endpoints\": [\n            {\n              \"transport_zone_name\": \"Overlay-TZ\"\n            }\n          ]\n        }\n      ],\n      \"transport_zone_endpoints\": [ ],\n      \"node_deployment_info\": {\n        \"resource_type\": \"HostNode\",\n        \"ip_addresses\": [\"10.114.200.12\"],\n        \"os_type\": \"ESXI\",\n        \"host_credential\": {\n          \"username\": \"root\",\n          \"password\": \"VMware1!\"\n        }\n      }\n    },\n    {\n      \"resource_type\": \"TransportNode\",\n      \"display_name\": \"esx7-c13\",\n      \"description\": \"Host Transport Node for esxi c13\",\n      \"host_switches\": [\n        {\n          \"host_switch_name\": \"nsxvswitch\",\n          \"host_switch_type\": \"NVDS\",\n          \"host_switch_mode\": \"STANDARD\",\n          \"host_switch_profiles\": [\n            {\n              \"name\": \"nsx-default-uplink-hostswitch-profile\",\n              \"type\": \"UplinkHostSwitchProfile\"\n            }\n          ],\n          \"pnics\": [\n            {\n              \"device_name\": \"vmnic1\",\n              \"uplink_name\": \"uplink-1\"\n            }\n          ],\n          \"ip_assignment_spec\": {\n            \"resource_type\": \"StaticIpPoolSpec\",\n            \"ip_pool_name\": \"TEP-IP-Pool\"\n          },\n          \"transport_zone_endpoints\": [\n            {\n              \"transport_zone_name\": \"Overlay-TZ\"\n            }\n          ]\n        }\n      ],\n      \"transport_zone_endpoints\": [ ],\n      \"node_deployment_info\": {\n        \"resource_type\": \"HostNode\",\n        \"ip_addresses\": [\"10.114.200.13\"],\n        \"os_type\": \"ESXI\",\n        \"host_credential\": {\n          \"username\": \"root\",\n          \"password\": \"VMware1!\"\n        }\n      }\n    }\n  ],\n\n  \"edge_clusters\": [\n    {\n      \"display_name\": \"Edge-Cluster-01\",\n      \"cluster_profile_bindings\": [\n        { \"profile_name\": \"nsx-default-edge-high-availability-profile\" }\n      ],\n      \"members\": [\n        { \"transport_node_name\": \"EdgeNode-01\" }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "tests/playbooks/topologies/setup_infra/setup_infra_vars_9x.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n#\n# Variables file for Day-0/1 setup\n# Creates the following:\n#   - 2 Transport Zones\n#   - 1 IP Pool (used by Edge)\n#   - 1 Transport Node Profile with 2 TZ endpoints\n#   - 2 Edge Transport Nodes\n#   - 2 ESX Host Transport Nodes\n#   - 1 Edge Cluster with the 2 Edge Nodes\n#\n{\n\n  #\n  # Flag to create or delete all the objects\n  # Accepts: 'present' to create; 'absent' to delete\n  #\n  \"state\": \"present\",\n\n  #\n  # Common NSX Appliance variables\n  #\n  \"nsx_username\": \"admin\",\n  \"nsx_password\": \"myPassword1!myPassword1!\",\n  \"validate_certs\": False,\n\n  #\n  # First NSX appliance node. Defined separate based on the consumption.\n  # Accepts both IP (IPv4) and FQDN for 'mgmt_ip'\n  #\n  \"nsx_node1\": {\n    \"hostname\": \"mynsx-01.mylab.local\",\n    \"mgmt_ip\": \"10.114.200.41\",\n    \"datacenter\": \"Datacenter\",\n    \"cluster\": \"Management\",\n    \"datastore\": \"datastore36\",\n    \"portgroup\": \"VM Network\"\n  },\n\n  \"transport_zones\": [\n    {\n      \"display_name\": \"Overlay-TZ\",\n      \"description\": \"NSX Configured Overlay Transport Zone\",\n      \"tz_type\": \"OVERLAY_BACKED\"\n    },\n    {\n      \"display_name\": \"VLAN-TZ\",\n      \"description\": \"NSX Configured VLAN Transport Zone\",\n      \"tz_type\": \"VLAN_BACKED\"\n    }\n  ],\n\n  \"ip_pools\": [\n    {\n      \"display_name\": \"TEP-IP-Pool\",\n      \"pool_static_subnets\": [\n        {\n          \"display_name\": \"TEP_ip_pool_subnet\",\n          \"state\": \"present\",\n          \"allocation_ranges\": [\n            {\n              \"start\": \"172.16.227.50\",\n              \"end\": \"172.16.227.59\"\n            }\n          ],\n          \"gateway_ip\": \"172.16.227.1\",\n          \"cidr\": \"172.16.227.0/24\"\n        }\n      ]\n    }\n  ],\n\n  \"transport_node_profiles\": [\n    {\n      \"display_name\": \"TNP-1\",\n      \"description\": \"Compute Transport Node Profile\",\n      \"host_switches\": [\n        {\n\n          \"host_switch_name\": \"vds7\",\n          \"host_switch_id\": \"50 35 17 4a 3d be 59 37-57 d0 0d 03 11 ae 7e a2\",\n          \"host_switch_type\": \"VDS\",\n          \"host_switch_mode\": \"STANDARD\",\n          \"host_switch_profiles\": [\n            {\n              \"name\": \"nsx-default-uplink-hostswitch-profile\",\n              \"type\": \"UplinkHostSwitchProfile\"\n            }\n          ],\n          \"pnics\": [],\n          \"uplinks\": [\n            {\n              \"vds_uplink_name\": \"Uplink 1\",\n              \"uplink_name\": \"uplink-1\"\n            },\n            {\n              \"vds_uplink_name\": \"Uplink 2\",\n              \"uplink_name\": \"uplink-2\"\n            }\n          ],\n          \"ip_assignment_spec\": {\n              \"resource_type\": \"StaticIpPoolSpec\",\n              \"ip_pool_name\": \"TEP-IP-Pool\"\n          },\n          \"transport_zone_endpoints\": [\n            {\n              \"transport_zone_name\": \"Overlay-TZ\"\n            }\n          ]\n        }\n      ]\n    }\n  ],\n\n\n  \"transport_node_collections\": [\n    {\n      \"state\": \"present\",\n      \"display_name\": \"workload-cluster-1-collection\",\n      \"description\": \"TNP for cluster1\",\n      \"resource_type\": \"TransportNodeCollection\",\n      \"compute_manager_name\": \"vcenter7\",\n      \"cluster_name\": \"workload-cluster1\",\n      \"transport_node_profile_name\": \"TNP-1\"\n    }\n  ],\n\n\n  \"transport_nodes\": [\n    {\n      \"display_name\": \"EdgeNode-01\",\n      \"description\": \"NSX Edge Node 01\",\n      \"host_switches\": [\n        {\n          \"host_switch_name\": \"nvds\",\n          \"host_switch_type\": \"NVDS\",\n          \"host_switch_mode\": \"STANDARD\",\n          \"host_switch_profiles\": [\n            {\n              \"name\": \"nsx-edge-single-nic-uplink-profile\",\n              \"type\": \"UplinkHostSwitchProfile\"\n            }\n          ],\n          \"pnics\": [\n            {\n              \"device_name\": \"fp-eth0\",\n              \"uplink_name\": \"uplink-1\"\n            }\n          ],\n          \"ip_assignment_spec\":\n            {\n              \"resource_type\": \"StaticIpPoolSpec\",\n              \"ip_pool_name\": \"TEP-IP-Pool\"\n            },\n          \"transport_zone_endpoints\": [\n            {\n              \"transport_zone_name\": \"Overlay-TZ\"\n            }\n          ]\n        }\n      ],\n      \"node_deployment_info\": {\n        \"deployment_type\": \"VIRTUAL_MACHINE\",\n        \"deployment_config\": {\n          \"form_factor\": \"SMALL\",\n          \"vm_deployment_config\": {\n            \"vc_name\": \"vcenter\",\n            \"vc_username\": \"administrator@madhu.local\",\n            \"vc_password\": \"VMware1!\",\n            \"storage\": \"datastore7\",\n            \"compute\": \"Management\",\n            \"host\": \"10.114.200.7\",\n            \"data_networks\": [\n              \"VM Network\",\n#              \"lab-dvpg\",\n#              \"lab-dvpg\"\n            ],\n            \"default_gateway_addresses\": [ \"10.114.200.1\" ],\n            \"management_network\": \"VM Network\",\n            \"management_port_subnets\": [\n              {\n                \"ip_addresses\": [ \"10.114.200.14\" ],\n                \"prefix_length\": 27\n              }\n            ],\n            \"placement_type\": \"VsphereDeploymentConfig\"\n          },\n          \"node_user_settings\": {\n            \"cli_username\": \"admin\" ,\n            \"root_password\": \"myPassword1!myPassword1!\",\n            \"cli_password\": \"myPassword1!myPassword1!\",\n            \"audit_username\": \"audit\",\n            \"audit_password\": \"myPassword1!myPassword1!\"\n          }\n        },\n        \"node_settings\": {\n          \"allow_ssh_root_login\": \"True\",\n          \"enable_ssh\": \"True\",\n          \"hostname\": \"edgenode-01.madhu.local\"\n        },\n        \"resource_type\": \"EdgeNode\",\n        \"display_name\": \"EdgeNode-01\"\n      }\n    },\n    {\n      \"resource_type\": \"TransportNode\",\n      \"display_name\": \"esx7-12\",\n      \"description\": \"Host Transport Node for ESXi7-12\",\n      \"host_switches\": [\n        {\n          \"host_switch_name\": \"nsxvswitch\",\n          \"host_switch_type\": \"NVDS\",\n          \"host_switch_mode\": \"STANDARD\",\n          \"host_switch_profiles\": [\n            {\n              \"name\": \"nsx-default-uplink-hostswitch-profile\",\n              \"type\": \"UplinkHostSwitchProfile\"\n            }\n          ],\n          \"pnics\": [\n            {\n              \"device_name\": \"vmnic1\",\n              \"uplink_name\": \"uplink-1\"\n            }\n          ],\n          \"ip_assignment_spec\": {\n            \"resource_type\": \"StaticIpPoolSpec\",\n            \"ip_pool_name\": \"TEP-IP-Pool\"\n          },\n          \"transport_zone_endpoints\": [\n            {\n              \"transport_zone_name\": \"Overlay-TZ\"\n            }\n          ]\n        }\n      ],\n      \"transport_zone_endpoints\": [ ],\n      \"node_deployment_info\": {\n        \"resource_type\": \"HostNode\",\n        \"ip_addresses\": [\"10.114.200.12\"],\n        \"os_type\": \"ESXI\",\n        \"host_credential\": {\n          \"username\": \"root\",\n          \"password\": \"VMware1!\"\n        }\n      }\n    },\n    {\n      \"resource_type\": \"TransportNode\",\n      \"display_name\": \"esx7-c13\",\n      \"description\": \"Host Transport Node for esxi c13\",\n      \"host_switches\": [\n        {\n          \"host_switch_name\": \"nsxvswitch\",\n          \"host_switch_type\": \"NVDS\",\n          \"host_switch_mode\": \"STANDARD\",\n          \"host_switch_profiles\": [\n            {\n              \"name\": \"nsx-default-uplink-hostswitch-profile\",\n              \"type\": \"UplinkHostSwitchProfile\"\n            }\n          ],\n          \"pnics\": [\n            {\n              \"device_name\": \"vmnic1\",\n              \"uplink_name\": \"uplink-1\"\n            }\n          ],\n          \"ip_assignment_spec\": {\n            \"resource_type\": \"StaticIpPoolSpec\",\n            \"ip_pool_name\": \"TEP-IP-Pool\"\n          },\n          \"transport_zone_endpoints\": [\n            {\n              \"transport_zone_name\": \"Overlay-TZ\"\n            }\n          ]\n        }\n      ],\n      \"transport_zone_endpoints\": [ ],\n      \"node_deployment_info\": {\n        \"resource_type\": \"HostNode\",\n        \"ip_addresses\": [\"10.114.200.13\"],\n        \"os_type\": \"ESXI\",\n        \"host_credential\": {\n          \"username\": \"root\",\n          \"password\": \"VMware1!\"\n        }\n      }\n    }\n  ],\n\n  \"edge_clusters\": [\n    {\n      \"display_name\": \"Edge-Cluster-01\",\n      \"cluster_profile_bindings\": [\n        { \"profile_name\": \"nsx-default-edge-high-availability-profile\" }\n      ],\n      \"members\": [\n        { \"transport_node_name\": \"EdgeNode-01\" }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/01_upgrade_upload_mub.yml",
    "content": "- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - upgrade_vars.yml\n  tasks:\n    - name: Upload MUB to NSX-T Manager\n      vmware.ansible_for_nsxt.nsxt_upgrade_upload_mub:\n        hostname: \"{{  nsx_manager  }}\"\n        username: \"{{  nsx_username  }}\"\n        password: \"{{  nsx_password  }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        url: \"{{ mub_url }}\"\n        timeout: \"{{ timeout }}\" \n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/02_upgrade_accept_eula.yml",
    "content": "- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - upgrade_vars.yml\n  tasks:\n    - name: Accepts EULA\n      vmware.ansible_for_nsxt.nsxt_upgrade_eula_accept:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/03_upgrade_uc.yml",
    "content": "- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - upgrade_vars.yml\n  tasks:\n    - name: Upgrade UC\n      vmware.ansible_for_nsxt.nsxt_upgrade_uc:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/04_upgrade_update_plan.yml",
    "content": "- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - upgrade_vars.yml\n  tasks:\n    - name: Update upgrade plan for Hosts\n      vmware.ansible_for_nsxt.nsxt_upgrade_plan:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        component_type: 'host'\n        parallel: False\n        pause_after_each_group: False\n        pause_on_error: True\n        state: 'present'\n    - name: Update upgrade plan for Edges\n      vmware.ansible_for_nsxt.nsxt_upgrade_plan:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        component_type: 'edge'\n        parallel: False\n        pause_after_each_group: False\n        pause_on_error: True\n        state: 'present'\n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/05_upgrade_update_groups.yml",
    "content": "- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - upgrade_vars.yml\n  tasks:\n    - name: Create upgrade groups\n      vmware.ansible_for_nsxt.nsxt_upgrade_groups:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        display_name: \"TestGroupAnsible\"\n        type: \"HOST\"\n        parallel: \"False\"\n        enabled: \"true\"\n        upgrade_units: \"{{ hosts }}\"\n        state: \"present\"\n#        extended_configuration:\n#          - key: \"upgrade_mode\"\n#            value: \"in_place\"\n#          - key: \"rebootless_upgrade\"\n#            value: \"true\"\n        extended_configuration:\n          - key: \"upgrade_mode\"\n            value: \"maintenance_mode\"\n          - key: \"rebootless_upgrade\"\n            value: \"true\"\n          - key: \"maintenance_mode_config_evacuate_powerd_off_vms\"\n            value: \"false\"\n        state: \"present\"\n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/06_upgrade_prechecks.yml",
    "content": "- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - upgrade_vars.yml\n  tasks:\n    - name: Run and abort upgrade prechecks\n      vmware.ansible_for_nsxt.nsxt_upgrade_prechecks:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        state: 'present'\n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/07_upgrade_run.yml",
    "content": "- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - upgrade_vars.yml\n  tasks:\n    - name: Runs Upgrade\n      vmware.ansible_for_nsxt.nsxt_upgrade_run:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password }}\"\n        validate_certs: \"{{ validate_certs }}\"\n        paused_upgrade: False\n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/README.md",
    "content": "# Upgrade NSX-T Cluster\n\n# Overview\nThe set of playbooks in this example does a full NSX upgrade (including\nHost Transport Nodes and Edge Transport Nodes). The playbooks\nare divided based on the workflow.\n\nThere are 7 main playbooks and a common variable files:\n\n* 01_upgrade_upload_mub.yml\n* 02_upgrade_accept_eula.yml\n* 03_upgrade_uc.yml\n* 04_upgrade_update_plan.yml\n* [ OPTIONAL ] 05_upgrade_update_groups.yml\n* 06_upgrade_prechecks.yml\n* 07_upgrade_run.yml\n* upgrade_vars.yml\n\nThe following playbooks can be used to check the status of different objects during\nthe upgrade process\n\ncheck_upgrade_groups_facts.yml\n\ncheck_upgrade_pre_post_checks_facts.yml\n\ncheck_upgrade_status_summary_facts.yml\n\n\nTo run the example, copy all the files two-levels up, edit the variables file\nto match your needs and run the playbooks in the order listed.\n\nValidated against:\n* NSX-T 2.5 GA --> NSX-T 2.5.1 GA\n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/check_upgrade_groups_facts.yml",
    "content": "- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - upgrade_vars.yml\n  tasks:\n    - name: Get upgrade groups info\n      vmware.ansible_for_nsxt.nsxt_upgrade_groups_facts:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password}}\"\n        validate_certs: \"{{ validate_certs }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/check_upgrade_pre_post_checks_facts.yml",
    "content": "- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - upgrade_vars.yml\n  tasks:\n    - name: Get upgrade pre and post checks info\n      vmware.ansible_for_nsxt.nsxt_upgrade_pre_post_checks_facts:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password}}\"\n        validate_certs: \"{{ validate_certs }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/check_upgrade_status_summary_facts.yml",
    "content": "- hosts: 127.0.0.1\n  connection: local\n  become: yes\n  vars_files:\n    - upgrade_vars.yml\n  tasks:\n    - name: Get upgrade status summary\n      vmware.ansible_for_nsxt.nsxt_upgrade_status_summary_facts:\n        hostname: \"{{ nsx_manager }}\"\n        username: \"{{ nsx_username }}\"\n        password: \"{{ nsx_password}}\"\n        validate_certs: \"{{ validate_certs }}\"\n"
  },
  {
    "path": "tests/playbooks/topologies/upgrade/upgrade_vars.yml",
    "content": "# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# Variables file for Upgrading NSX-T:\n#   - NSX-T Cluster\n#   - Transport Nodes (Edge and Host)\n#\n{\n\n  #\n  # Common NSX Appliance variables\n  #\n  \"nsx_manager\": \"10.114.200.11\",\n  \"nsx_username\": \"admin\",\n  \"nsx_password\": \"myPassword1!myPassword1!\",\n  \"validate_certs\": False,\n\n  # Upgrade MUB\n  \"mub_url\": \"http://10.114.200.8/VMware-NSX-upgrade-bundle-2.5.0.1.0.14938184.mub\",\n  \"timeout\": 9000,\n\n  # Display names of the hosts as seen by NSX which are to be upgraded\n  hosts: [\n    {\n      \"host_name\": \"esx-c14\"\n    },\n    {\n      \"host_name\": \"esx-c15\"\n    }\n  ]\n\n}\n"
  },
  {
    "path": "tests/unit/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit/plugins/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit/plugins/module_utils/__init__.py",
    "content": ""
  },
  {
    "path": "tests/unit/plugins/module_utils/test_nsxt_base_resource.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\nimport unittest\nimport json\nfrom unittest.mock import Mock, patch\n\nfrom shutil import copyfile\nimport ansible.module_utils.basic as ansible_basic\n\nimport sys\n\nimport os\n\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.policy_communicator import PolicyCommunicator\nimport ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.nsxt_base_resource as nsxt_base_resource\n\n\nclass SimpleDummyNSXTResource(nsxt_base_resource.NSXTBaseRealizableResource):\n    def __init__(self):\n        self.existing_resource_revision = 0\n        self.resource_class = self.__class__\n        self.validate_certs = False\n        self.baseline_args = {}\n\n    @staticmethod\n    def get_resource_base_url(baseline_args=None):\n        return 'dummy'\n\n    @staticmethod\n    def get_resource_spec():\n        return {\n            \"dummy\": dict(\n                required=False\n            )\n        }\n\n\nclass NestedDummyNSXTResource(nsxt_base_resource.NSXTBaseRealizableResource):\n    def __init__(self):\n        self.existing_resource_revision = 0\n        self.resource_class = self.__class__\n        self.validate_certs = False\n        self.baseline_args = {}\n\n    @staticmethod\n    def get_resource_base_url(baseline_args=None):\n        return 'dummy'\n\n    @staticmethod\n    def get_resource_spec():\n        return {\n            \"dummy\": dict(\n                required=False\n            )\n        }\n\n    class SubDummyResource1(nsxt_base_resource.NSXTBaseRealizableResource):\n        # This one does not override get_spec_identifier\n        def __init__(self):\n            self.existing_resource_revision = 0\n            NestedDummyNSXTResource.__init__(self)\n\n        @staticmethod\n        def get_resource_update_priority():\n            # Will be updated first\n            return 3\n\n        @staticmethod\n        def get_resource_base_url():\n            return 'sub_dummy1'\n\n        @staticmethod\n        def get_resource_base_url(parent_info):\n            parent_id = parent_info.get(\n                \"NestedDummyNSXTResource_id\", 'default')\n            return '{}-sub_dummy1'.format(parent_id)\n\n        @staticmethod\n        def get_resource_spec():\n            return {\n                \"sub_dummy1\": dict(\n                    required=True\n                )\n            }\n\n        def achieve_subresource_state_if_del_parent(self):\n            # return True if the resource is to be realized with its own\n            # specified state irrespective of the state of its parent resource.\n            return True\n\n    class SubDummyResource2(nsxt_base_resource.NSXTBaseRealizableResource):\n        # This one overrides get_spec_identifier\n        def __init__(self):\n            self.existing_resource_revision = 0\n            NestedDummyNSXTResource.__init__(self)\n\n        @staticmethod\n        def get_resource_update_priority():\n            # Will be updated second\n            return 2\n\n        def get_spec_identifier(self):\n            return (\n                NestedDummyNSXTResource.SubDummyResource2.\n                get_spec_identifier())\n\n        @classmethod\n        def get_spec_identifier(cls):\n            return \"sub_dummy_res_2\"\n\n        @staticmethod\n        def get_resource_base_url(parent_info):\n            parent_id = parent_info.get(\n                \"NestedDummyNSXTResource_id\", 'default')\n            return '{}-sub_dummy2'.format(parent_id)\n\n        @staticmethod\n        def get_resource_spec():\n            return {\n                \"sub_dummy2\": dict(\n                    required=True\n                )\n            }\n\n    class SubDummyResource3(nsxt_base_resource.NSXTBaseRealizableResource):\n        # This one overrides get_spec_identifier\n        # and supports creation of only 1 instance per parent resource\n        def __init__(self):\n            self.existing_resource_revision = 0\n            NestedDummyNSXTResource.__init__(self)\n\n        @staticmethod\n        def get_resource_update_priority():\n            # Will be updated third\n            return 1\n\n        def get_spec_identifier(self):\n            return (\n                NestedDummyNSXTResource.SubDummyResource2.\n                get_spec_identifier())\n\n        @classmethod\n        def get_spec_identifier(cls):\n            return \"sub_dummy_res_3\"\n\n        @classmethod\n        def allows_multiple_resource_spec(cls):\n            return False\n\n        @staticmethod\n        def get_resource_base_url(parent_info):\n            parent_id = parent_info.get(\n                \"NestedDummyNSXTResource_id\", 'default')\n            return '{}-sub_dummy3'.format(parent_id)\n\n        @staticmethod\n        def get_resource_spec():\n            return {\n                \"sub_dummy3\": dict(\n                    required=True\n                )\n            }\n\n\nclass MockAnsible(object):\n    def __init__(self, params={}, check_mode=False):\n        self.params = params\n        self.check_mode = check_mode\n\n    def fail_json(self, *args, **kwargs):\n        pass\n\n    def exit_json(self, *args, **kwargs):\n        pass\n\n\nclass NSXTBaseRealizableResourceTestCase(unittest.TestCase):\n    def setUp(self):\n        self.init_base_resources = nsxt_base_resource.BASE_RESOURCES\n        return super().setUp()\n\n    def tearDown(self):\n        nsxt_base_resource.BASE_RESOURCES = self.init_base_resources\n        return super().tearDown()\n\n    @patch('ansible_collections.vmware.ansible_for_nsxt.plugins.'\n           'module_utils.nsxt_base_resource.PolicyCommunicator')\n    def test_realize(self, mock_policy_communicator):\n        init_base_resources = nsxt_base_resource.BASE_RESOURCES\n        nsxt_base_resource.BASE_RESOURCES = {\"NestedDummyNSXTResource\"}\n\n        nested_dummy_resource = NestedDummyNSXTResource()\n        nested_dummy_resource.resource_class = nested_dummy_resource.__class__\n\n        mock_policy_communicator_instance = Mock()\n\n        mock_policy_communicator.get_instance.return_value = (\n            mock_policy_communicator_instance)\n\n        mock_policy_communicator_instance.request.return_value = (200, \"OK\")\n\n        my_params = {}\n        mock_ansible_module = MockAnsible(params=my_params)\n        nested_dummy_resource.module = mock_ansible_module\n\n        def test_create():\n            # when all resources state is present\n            nonlocal my_params\n            my_params.clear()\n            my_params.update({\n                \"hostname\": \"dummy\",\n                \"username\": \"dummy\",\n                \"password\": \"dummy\",\n                \"nsx_cert_path\": None,\n                \"nsx_key_path\": None,\n                \"request_headers\": None,\n                \"ca_path\": None,\n                \"validate_certs\": False,\n                \"state\": \"present\",\n                \"id\": \"dummy\",\n                \"SubDummyResource1\": [\n                    {\n                        \"state\": \"present\",\n                        \"id\": \"dummy1\"\n                    }\n                ],\n                \"sub_dummy_res_2\": [\n                    {\n                        \"state\": \"present\",\n                        \"id\": \"dummy2-1\",\n                    },\n                    {\n                        \"state\": \"present\",\n                        \"id\": \"dummy2-2\",\n                    }\n                ],\n                \"sub_dummy_res_3\": {\n                    \"state\": \"present\",\n                    \"id\": \"dummy3\",\n                },\n            })\n            expected_exec_logs = [\n                {\n                    'body': 'OK',\n                    'resource_type': 'NestedDummyNSXTResource',\n                    'message': ('NestedDummyNSXTResource with id dummy'\n                                ' created.'),\n                    'changed': True,\n                    'id': 'dummy'\n                },\n                {\n                    'body': 'OK',\n                    'resource_type': 'SubDummyResource1',\n                    'message': 'SubDummyResource1 with id dummy1 created.',\n                    'changed': True,\n                    'id': 'dummy1'\n                },\n                {\n                    'body': 'OK',\n                    'resource_type': 'SubDummyResource2',\n                    'message': 'SubDummyResource2 with id dummy2-1 created.',\n                    'changed': True,\n                    'id': 'dummy2-1'\n                },\n                {\n                    'body': 'OK',\n                    'resource_type': 'SubDummyResource2',\n                    'message': 'SubDummyResource2 with id dummy2-2 created.',\n                    'changed': True,\n                    'id': 'dummy2-2'\n                },\n                {\n                    'body': 'OK',\n                    'resource_type': 'SubDummyResource3',\n                    'message': 'SubDummyResource3 with id dummy3 created.',\n                    'changed': True,\n                    'id': 'dummy3'\n                }\n            ]\n\n            def test_create_base_resource_first():\n                exec_logs = []\n                nested_dummy_resource.realize(\n                    successful_resource_exec_logs=exec_logs)\n                self.assertEqual(exec_logs[0], expected_exec_logs[0])\n                self.assertEqual(exec_logs[1], expected_exec_logs[1])\n                self.assertCountEqual(exec_logs[2:4], expected_exec_logs[2:4])\n                self.assertEqual(exec_logs[4], expected_exec_logs[4])\n\n            def test_create_sub_resource_first():\n                nonlocal my_params\n                my_params['id'] = 'dummy'\n                my_params['create_or_update_subresource_first'] = True\n                my_params[\"SubDummyResource1\"][0][\"id\"] = \"dummy1\"\n                my_params[\"sub_dummy_res_2\"][0][\"display_name\"] = \"dummy2-1\"\n                my_params[\"sub_dummy_res_2\"][1][\"display_name\"] = \"dummy2-2\"\n                my_params[\"sub_dummy_res_3\"][\"display_name\"] = \"dummy3\"\n                exec_logs = []\n                nested_dummy_resource.realize(\n                    successful_resource_exec_logs=exec_logs)\n                self.assertEqual(exec_logs[0], expected_exec_logs[1])\n                self.assertCountEqual(exec_logs[1:3], expected_exec_logs[2:4])\n                self.assertEqual(exec_logs[3], expected_exec_logs[4])\n                self.assertEqual(exec_logs[4], expected_exec_logs[0])\n\n            test_create_base_resource_first()\n            test_create_sub_resource_first()\n\n        def test_delete():\n            # when all resources state is absent\n            nonlocal my_params\n            my_params.clear()\n            my_params.update({\n                \"hostname\": \"dummy\",\n                \"username\": \"dummy\",\n                \"password\": \"dummy\",\n                \"nsx_cert_path\": None,\n                \"nsx_key_path\": None,\n                \"request_headers\": None,\n                \"ca_path\": None,\n                \"validate_certs\": False,\n                \"state\": \"absent\",\n                \"id\": \"dummy\",\n                \"SubDummyResource1\": [\n                    {\n                        \"state\": \"absent\",\n                        \"id\": \"dummy1\"\n                    }\n                ],\n                \"sub_dummy_res_2\": [\n                    {\n                        \"state\": \"absent\",\n                        \"id\": \"dummy2-1\"\n                    },\n                    {\n                        \"state\": \"absent\",\n                        \"id\": \"dummy2-2\"\n                    },\n                ],\n                \"sub_dummy_res_3\": {\n                    \"state\": \"absent\",\n                    \"id\": \"dummy3\"\n                }\n            })\n            expected_exec_logs = [\n                {\n                    'msg': 'No SubDummyResource1 exist with id dummy1',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource1'\n                },\n                {\n                    'msg': 'No SubDummyResource2 exist with id dummy2-1',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource2'\n                },\n                {\n                    'msg': 'No SubDummyResource2 exist with id dummy2-2',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource2'\n                },\n                {\n                    'msg': 'No SubDummyResource3 exist with id dummy3',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource3'\n                },\n                {\n                    'msg': 'No NestedDummyNSXTResource exist with id dummy',\n                    'changed': False,\n                    'resource_type': 'NestedDummyNSXTResource'\n                }\n            ]\n\n            def test_delete_base_resource_first():\n                nonlocal my_params\n                my_params['delete_subresource_first'] = False\n                exec_logs = []\n                nested_dummy_resource.realize(\n                    successful_resource_exec_logs=exec_logs)\n                self.assertEqual(exec_logs[0], expected_exec_logs[4])\n                self.assertEqual(exec_logs[1], expected_exec_logs[3])\n                self.assertEqual(exec_logs[2:4], expected_exec_logs[1:3])\n                self.assertEqual(exec_logs[4], expected_exec_logs[0])\n\n            def test_delete_sub_resource_first():\n                nonlocal my_params\n                my_params['display_name'] = 'dummy'\n                del my_params['delete_subresource_first']\n                # SubDummyResource1_id and sub_dummy_res_2_display_name are\n                # deleted from params. Specify them using display_name.\n                # This also tests that user can specify either id or\n                # display_name to identify resource.\n                my_params[\"SubDummyResource1\"][0][\"display_name\"] = \"dummy1\"\n                my_params[\"sub_dummy_res_2\"][0][\"display_name\"] = \"dummy2-1\"\n                my_params[\"sub_dummy_res_2\"][1][\"display_name\"] = \"dummy2-2\"\n                my_params[\"sub_dummy_res_3\"][\"display_name\"] = \"dummy3\"\n                exec_logs = []\n                nested_dummy_resource.realize(\n                    successful_resource_exec_logs=exec_logs)\n                self.assertEqual(exec_logs[0], expected_exec_logs[3])\n                self.assertEqual(exec_logs[1:3], expected_exec_logs[1:3])\n                self.assertEqual(exec_logs[3], expected_exec_logs[0])\n                self.assertEqual(exec_logs[4], expected_exec_logs[4])\n\n            test_delete_base_resource_first()\n            test_delete_sub_resource_first()\n\n        def test_detached_delete_parent():\n            # when parent is absent but child is present\n            nonlocal my_params\n            my_params.clear()\n            my_params.update({\n                \"hostname\": \"dummy\",\n                \"username\": \"dummy\",\n                \"password\": \"dummy\",\n                \"nsx_cert_path\": None,\n                \"nsx_key_path\": None,\n                \"request_headers\": None,\n                \"ca_path\": None,\n                \"validate_certs\": False,\n                \"state\": \"absent\",\n                \"id\": \"dummy\",\n                \"SubDummyResource1\": [\n                    {\n                        \"state\": \"absent\",\n                        \"id\": \"dummy1\"\n                    }\n                ],\n                \"sub_dummy_res_2\": [\n                    {\n                        \"state\": \"present\",\n                        \"id\": \"dummy2-1\"\n                    },\n                    {\n                        \"state\": \"present\",\n                        \"id\": \"dummy2-2\"\n                    },\n                ],\n                \"sub_dummy_res_3\": {\n                    \"state\": \"absent\",\n                    \"id\": \"dummy3\"\n                }\n            })\n            expected_exec_logs = [\n                {\n                    'msg': 'No SubDummyResource1 exist with id dummy1',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource1'\n                },\n                {\n                    'msg': 'No SubDummyResource2 exist with id dummy2-1',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource2'\n                },\n                {\n                    'msg': 'No SubDummyResource2 exist with id dummy2-2',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource2'\n                },\n                {\n                    'msg': 'No SubDummyResource3 exist with id dummy3',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource3'\n                },\n                {\n                    'msg': 'No NestedDummyNSXTResource exist with id dummy',\n                    'changed': False,\n                    'resource_type': 'NestedDummyNSXTResource'\n                },\n                {\n                    'body': 'OK',\n                    'resource_type': 'SubDummyResource2',\n                    'message': 'SubDummyResource2 with id dummy2-1 created.',\n                    'changed': True,\n                    'id': 'dummy2-1'\n                },\n                {\n                    'body': 'OK',\n                    'resource_type': 'SubDummyResource2',\n                    'message': 'SubDummyResource2 with id dummy2-2 created.',\n                    'changed': True,\n                    'id': 'dummy2-2'\n                }\n            ]\n\n            def test_without_flag_achieve_subresource_state_if_del_parent():\n                exec_logs = []\n                nested_dummy_resource.realize(\n                    successful_resource_exec_logs=exec_logs)\n                self.assertEqual(exec_logs[0], expected_exec_logs[3])\n                self.assertEqual(exec_logs[1:3], expected_exec_logs[1:3])\n                self.assertEqual(exec_logs[3], expected_exec_logs[0])\n                self.assertEqual(exec_logs[4], expected_exec_logs[4])\n\n            def test_with_flag_achieve_subresource_state_if_del_parent():\n                nonlocal my_params\n                my_params['achieve_subresource_state_if_del_parent'] = True\n                # Test that user can specify either id or\n                # display_name to identify resource.\n                my_params['display_name'] = 'dummy'\n                my_params[\"SubDummyResource1\"][0][\"display_name\"] = \"dummy1\"\n                my_params[\"sub_dummy_res_2\"][0][\"display_name\"] = \"dummy2-1\"\n                my_params[\"sub_dummy_res_2\"][0][\n                    \"achieve_subresource_state_if_del_parent\"] = True\n                my_params[\"sub_dummy_res_2\"][1][\"display_name\"] = \"dummy2-2\"\n                my_params[\"sub_dummy_res_2\"][1][\n                    \"achieve_subresource_state_if_del_parent\"] = True\n                my_params[\"sub_dummy_res_3\"][\"display_name\"] = \"dummy3\"\n                exec_logs = []\n                nested_dummy_resource.realize(\n                    successful_resource_exec_logs=exec_logs)\n                print(exec_logs)\n                self.assertEqual(exec_logs[0], expected_exec_logs[3])\n                self.assertEqual(exec_logs[1:3], expected_exec_logs[5:])\n                self.assertEqual(exec_logs[3], expected_exec_logs[0])\n                self.assertEqual(exec_logs[4], expected_exec_logs[4])\n\n            test_without_flag_achieve_subresource_state_if_del_parent()\n            test_with_flag_achieve_subresource_state_if_del_parent()\n\n        def test_detached_delete_child():\n            # when parent is present but child is absent\n            nonlocal my_params\n            my_params.clear()\n            my_params.update({\n                \"hostname\": \"dummy\",\n                \"username\": \"dummy\",\n                \"password\": \"dummy\",\n                \"nsx_cert_path\": None,\n                \"nsx_key_path\": None,\n                \"request_headers\": None,\n                \"ca_path\": None,\n                \"validate_certs\": False,\n                \"state\": \"present\",\n                \"id\": \"dummy\",\n                \"SubDummyResource1\": [\n                    {\n                        \"state\": \"absent\",\n                        \"id\": \"dummy1\"\n                    }\n                ],\n                \"sub_dummy_res_2\": [\n                    {\n                        \"state\": \"absent\",\n                        \"id\": \"dummy2-1\"\n                    },\n                    {\n                        \"state\": \"absent\",\n                        \"id\": \"dummy2-2\"\n                    },\n                ],\n                \"sub_dummy_res_3\": {\n                    \"state\": \"absent\",\n                    \"id\": \"dummy3\"\n                }\n            })\n            expected_exec_logs = [\n                {\n                    'msg': 'No SubDummyResource1 exist with id dummy1',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource1'\n                },\n                {\n                    'msg': 'No SubDummyResource2 exist with id dummy2-1',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource2'\n                },\n                {\n                    'msg': 'No SubDummyResource2 exist with id dummy2-2',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource2'\n                },\n                {\n                    'msg': 'No SubDummyResource3 exist with id dummy3',\n                    'changed': False,\n                    'resource_type': 'SubDummyResource3'\n                },\n                {\n                    'msg': 'No NestedDummyNSXTResource exist with id dummy',\n                    'changed': False,\n                    'resource_type': 'NestedDummyNSXTResource'\n                },\n                {\n                    'body': 'OK',\n                    'resource_type': 'NestedDummyNSXTResource',\n                    'message': ('NestedDummyNSXTResource with id dummy'\n                                ' created.'),\n                    'changed': True,\n                    'id': 'dummy'\n                }\n            ]\n\n            exec_logs = []\n            nested_dummy_resource.realize(\n                successful_resource_exec_logs=exec_logs)\n            print(exec_logs)\n            self.assertEqual(exec_logs[0], expected_exec_logs[5])\n            self.assertEqual(exec_logs[1], expected_exec_logs[0])\n            self.assertEqual(exec_logs[2:4], expected_exec_logs[1:3])\n            self.assertEqual(exec_logs[4], expected_exec_logs[3])\n\n        test_create()\n        test_delete()\n        test_detached_delete_parent()\n        test_detached_delete_child()\n\n        nsxt_base_resource.BASE_RESOURCES = init_base_resources\n\n    def test_check_for_update(self):\n        simple_dummy_resource = SimpleDummyNSXTResource()\n\n        def test_with_no_existing_resource():\n            self.assertFalse(simple_dummy_resource.check_for_update(\n                None, \"dummy\"))\n\n        def test_with_same_params():\n            existing_params = {\"dummy\": \"dummy\"}\n            resource_params = {\"dummy\": \"dummy\"}\n\n            self.assertFalse(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n        def test_with_diff_params_simple():\n            existing_params = {\"dummy\": \"dummy\"}\n            resource_params = {\"dummy1\": \"dummy\"}\n\n            self.assertTrue(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n        def test_with_same_params_list_same_order():\n            existing_params = {\"dummy\": [\"dummy1\", \"dummy2\"]}\n            resource_params = {\"dummy\": [\"dummy1\", \"dummy2\"]}\n\n            self.assertFalse(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n        def test_with_same_params_list_different_order():\n            existing_params = {\"dummy\": [\"dummy1\", \"dummy2\"]}\n            resource_params = {\"dummy\": [\"dummy2\", \"dummy1\"]}\n\n            self.assertFalse(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n        def test_with_same_params_single_dict():\n            existing_params = {\"dummy\": {\"dummy\": \"dummy\"}}\n            resource_params = {\"dummy\": {\"dummy\": \"dummy\"}}\n\n            self.assertFalse(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n        def test_with_diff_params_single_dict():\n            existing_params = {\"dummy\": {\"dummy\": \"dummy\"}}\n            resource_params = {\"dummy\": {\"dummy1\": \"dummy\"}}\n\n            self.assertTrue(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n            existing_params = {\"dummy\": {\"dummy\": \"dummy\"}}\n            resource_params = {\"dummy\": {\"dummy\": \"dummy1\"}}\n\n            self.assertTrue(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n            existing_params = {\"dummy\": {\"dummy\": \"dummy\"}}\n            resource_params = {\"dummy1\": {\"dummy\": \"dummy\"}}\n\n            self.assertTrue(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n        def test_with_same_params_multilevel_dict():\n            existing_params = {\"dummy\": {\"dummy\": {\"dummy\": \"dummy\"}}}\n            resource_params = {\"dummy\": {\"dummy\": {\"dummy\": \"dummy\"}}}\n\n            self.assertFalse(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n        def test_with_diff_params_multilevel_dict():\n            existing_params = {\"dummy\": {\"dummy\": {\"dummy\": \"dummy\"}}}\n            resource_params = {\"dummy1\": {\"dummy\": {\"dummy\": \"dummy\"}}}\n\n            self.assertTrue(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n            existing_params = {\"dummy\": {\"dummy\": {\"dummy\": \"dummy\"}}}\n            resource_params = {\"dummy\": {\"dummy1\": {\"dummy\": \"dummy\"}}}\n\n            self.assertTrue(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n            existing_params = {\"dummy\": {\"dummy\": {\"dummy\": \"dummy\"}}}\n            resource_params = {\"dummy\": {\"dummy\": {\"dummy1\": \"dummy\"}}}\n\n            self.assertTrue(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n            existing_params = {\"dummy\": {\"dummy\": {\"dummy\": \"dummy\"}}}\n            resource_params = {\"dummy\": {\"dummy\": {\"dummy\": \"dummy1\"}}}\n\n            self.assertTrue(simple_dummy_resource.check_for_update(\n                existing_params, resource_params))\n\n        test_with_no_existing_resource()\n        test_with_same_params()\n        test_with_diff_params_simple()\n        test_with_same_params_list_same_order()\n        test_with_same_params_list_different_order()\n        test_with_same_params_single_dict()\n        test_with_diff_params_single_dict()\n        test_with_same_params_multilevel_dict()\n        test_with_diff_params_multilevel_dict()\n\n    def test_get_attribute(self):\n        simple_dummy_resource = SimpleDummyNSXTResource()\n\n        mock_ansible_module = MockAnsible()\n        simple_dummy_resource.module = mock_ansible_module\n        init_base_resources = nsxt_base_resource.BASE_RESOURCES\n        nsxt_base_resource.BASE_RESOURCES = {\"SimpleDummyNSXTResource\"}\n        resource_params = {\n            \"dummy\": \"dummy\"\n        }\n        mock_ansible_module.params = resource_params\n        expected_value = \"dummy\"\n        observed_value = simple_dummy_resource.get_attribute(\n            \"dummy\", resource_params)\n        self.assertEqual(expected_value, observed_value)\n\n        expected_value = (nsxt_base_resource.NSXTBaseRealizableResource.\n                          INCORRECT_ARGUMENT_NAME_VALUE)\n        observed_value = simple_dummy_resource.get_attribute(\n            \"dummy2\", resource_params)\n        self.assertEqual(expected_value, observed_value)\n\n    def test_extract_nsx_resource_params(self):\n        simple_dummy_resource = SimpleDummyNSXTResource()\n\n        resource_params = {\n            # Note that AnsibleModule can have >= keys than the spec\n            \"dummy\": \"dummy\",\n            \"redundant_dummy\": \"dummy\"\n        }\n\n        expected_params = {\n            \"dummy\": \"dummy\"\n        }\n\n        observed_params = (\n            simple_dummy_resource._extract_nsx_resource_params(\n                resource_params))\n\n        self.assertEqual(expected_params, observed_params)\n\n    @patch('ansible_collections.vmware.ansible_for_nsxt.plugins.'\n           'module_utils.nsxt_base_resource.PolicyCommunicator')\n    def test_send_request_to_API(self, mock_policy_communicator):\n        mock_policy_communicator.request.return_value = (200, \"OK\")\n        mock_policy_communicator.get_all_results.return_value = (200, \"OK\")\n\n        init_base_resources = nsxt_base_resource.BASE_RESOURCES\n        nsxt_base_resource.BASE_RESOURCES = {\"NestedDummyNSXTResource\"}\n\n        # Test get all resources\n        nested_dummy_resource = NestedDummyNSXTResource()\n        nested_dummy_resource.policy_communicator = mock_policy_communicator\n        nested_dummy_resource.validate_certs = False\n        nested_dummy_resource.resource_class = nested_dummy_resource.__class__\n        nested_dummy_resource._send_request_to_API()\n        self.assertEqual(\n            mock_policy_communicator.get_all_results.call_count, 1)\n        self.assertEqual(mock_policy_communicator.request.call_count, 0)\n\n        # Test Base Resource\n        mock_policy_communicator.reset_mock()\n        nested_dummy_resource = NestedDummyNSXTResource()\n        nested_dummy_resource.policy_communicator = mock_policy_communicator\n        nested_dummy_resource.validate_certs = False\n        nested_dummy_resource.resource_class = nested_dummy_resource.__class__\n        nested_dummy_resource._send_request_to_API(suffix=\"dummy\")\n        self.assertEqual(mock_policy_communicator.request.call_count, 1)\n\n        # Test Sub-Resource\n        mock_policy_communicator.reset_mock()\n        nested_subdummy_resource1 = (\n            NestedDummyNSXTResource.SubDummyResource1())\n        nested_subdummy_resource1.policy_communicator = (\n            mock_policy_communicator)\n        nested_subdummy_resource1.validate_certs = False\n        nested_subdummy_resource1.resource_class = (\n            nested_subdummy_resource1.__class__)\n        nested_subdummy_resource1._parent_info = {\n            \"NestedDummyNSXTResource_id\": \"dummy\"\n        }\n        nested_subdummy_resource1._send_request_to_API(suffix=\"dummy\")\n\n        self.assertEqual(mock_policy_communicator.request.call_count, 1)\n\n        # Test when request throws exception\n        with self.assertRaises(Exception):\n            mock_policy_communicator.request = Mock()\n            mock_policy_communicator.request.raiseError.side_effect = Mock(\n                side_effect=Exception)\n\n            nested_dummy_resource = NestedDummyNSXTResource()\n            nested_dummy_resource.policy_communicator = (\n                mock_policy_communicator)\n            nested_dummy_resource.validate_certs = False\n            nested_dummy_resource.resource_class = (\n                nested_dummy_resource.__class__)\n            nested_dummy_resource._send_request_to_API(suffix=\"dummy\")\n\n        self.assertEqual(mock_policy_communicator.request.call_count, 1)\n        self.assertEqual(\n            mock_policy_communicator.get_all_results.call_count, 0)\n\n        nsxt_base_resource.BASE_RESOURCES = init_base_resources\n\n    @patch('ansible_collections.vmware.ansible_for_nsxt.plugins.'\n           'module_utils.nsxt_base_resource.PolicyCommunicator')\n    def test_achieve_present_state(self, mock_policy_communicator):\n        init_base_resources = nsxt_base_resource.BASE_RESOURCES\n        nsxt_base_resource.BASE_RESOURCES = {\"SimpleDummyNSXTResource\"}\n        simple_dummy_resource = SimpleDummyNSXTResource()\n        simple_dummy_resource.id = \"dummy\"\n        simple_dummy_resource.policy_communicator = mock_policy_communicator\n        simple_dummy_resource.module = MockAnsible()\n        simple_dummy_resource.existing_resource = {\n            \"_revision\": 1\n        }\n\n        def test_when_resource_not_updated():\n            simple_dummy_resource.nsx_resource_params = {}\n            exec_logs = []\n            # mock_policy_communicator.request.return_value = None\n            simple_dummy_resource._achieve_present_state(exec_logs)\n\n            self.assertEqual(mock_policy_communicator.request.call_count, 0)\n\n            expected_exec_logs = [\n                {\n                    \"changed\": False,\n                    \"id\": simple_dummy_resource.id,\n                    \"message\": \"%s with id %s already exists.\" %\n                    (simple_dummy_resource.__class__.__name__,\n                     simple_dummy_resource.id),\n                    \"resource_type\": simple_dummy_resource.__class__.__name__\n                }\n            ]\n            self.assertEqual(exec_logs, expected_exec_logs)\n\n        policy_communicator_request_call_num = 2\n\n        def test_when_resource_updated(is_created=False):\n            def test_when_policy_request_succeeds():\n                nonlocal policy_communicator_request_call_num\n                simple_dummy_resource.nsx_resource_params = {\n                    \"dummy\": \"dummy\"\n                }\n                simple_dummy_resource.resource_params = {}\n                exec_logs = []\n                mock_policy_communicator.request.side_effect = [\n                    (200, \"OK\"),\n                    (200, {\n                        \"_revision\": 1\n                    })\n                ]\n                simple_dummy_resource._achieve_present_state(exec_logs)\n\n                self.assertEqual(mock_policy_communicator.request.call_count,\n                                 policy_communicator_request_call_num)\n                policy_communicator_request_call_num += 1\n\n                if is_created:\n                    expected_message = (\"%s with id %s created.\" %\n                                        (simple_dummy_resource.__class__.\n                                         __name__, simple_dummy_resource.id))\n                else:\n                    expected_message = (\"%s with id %s updated.\" %\n                                        (simple_dummy_resource.__class__.\n                                         __name__, simple_dummy_resource.id))\n\n                expected_exec_logs = [\n                    {\n                        \"changed\": True,\n                        \"id\": simple_dummy_resource.id,\n                        \"body\": \"OK\",\n                        \"message\": expected_message,\n                        \"resource_type\": (\n                            simple_dummy_resource.__class__.__name__)\n                    }\n                ]\n                self.assertEqual(exec_logs, expected_exec_logs)\n\n            def test_when_policy_request_fails():\n                nonlocal policy_communicator_request_call_num\n                simple_dummy_resource.nsx_resource_params = {\n                    \"dummy\": \"dummy\"\n                }\n                exec_logs = []\n                mock_policy_communicator.request.return_value = Mock(\n                    side_effect=Exception)\n                simple_dummy_resource._achieve_present_state(exec_logs)\n                self.assertEqual(\n                    mock_policy_communicator.request.call_count,\n                    policy_communicator_request_call_num)\n                policy_communicator_request_call_num += 1\n\n            test_when_policy_request_succeeds()\n            test_when_policy_request_fails()\n            nonlocal policy_communicator_request_call_num\n\n        def test_create_new_resource():\n            simple_dummy_resource.existing_resource = None\n            test_when_resource_updated(is_created=True)\n\n        test_when_resource_not_updated()\n        test_when_resource_updated()\n        test_create_new_resource()\n        nsxt_base_resource.BASE_RESOURCES = init_base_resources\n\n    @patch('ansible_collections.vmware.ansible_for_nsxt.plugins.'\n           'module_utils.nsxt_base_resource.PolicyCommunicator')\n    def test_achieve_absent_state(self, mock_policy_communicator):\n        init_base_resources = nsxt_base_resource.BASE_RESOURCES\n        nsxt_base_resource.BASE_RESOURCES = {\"SimpleDummyNSXTResource\"}\n        simple_dummy_resource = SimpleDummyNSXTResource()\n        simple_dummy_resource.id = \"dummy\"\n        simple_dummy_resource.policy_communicator = mock_policy_communicator\n        simple_dummy_resource.module = MockAnsible()\n\n        def test_when_resource_exists_but_policy_request_fails():\n            simple_dummy_resource.existing_resource = {}\n            mock_policy_communicator.request.return_value = Mock(\n                side_effect=Exception)\n\n            exec_logs = []\n            expected_exec_logs = []\n\n            simple_dummy_resource._achieve_absent_state(exec_logs)\n\n            self.assertEqual(exec_logs, expected_exec_logs)\n\n        def test_when_resource_exists_and_policy_request_succeeds():\n            simple_dummy_resource.existing_resource = {}\n            mock_policy_communicator.request.side_effect = [\n                (200, \"OK\"),\n                Mock(side_effect=Exception)\n            ]\n\n            exec_logs = []\n            expected_exec_logs = [\n                {\n                    \"changed\": True,\n                    \"id\": simple_dummy_resource.id,\n                    \"message\": \"%s with id %s deleted.\" %\n                    (simple_dummy_resource.__class__.__name__,\n                     simple_dummy_resource.id)\n                }\n            ]\n\n            simple_dummy_resource._achieve_absent_state(exec_logs)\n\n            self.assertEqual(exec_logs, expected_exec_logs)\n\n        def test_when_resource_does_not_exist():\n            simple_dummy_resource.existing_resource = None\n\n            exec_logs = []\n            expected_exec_logs = [\n                {\n                    \"changed\": False,\n                    \"msg\": 'No %s exist with id %s' %\n                    (simple_dummy_resource.__class__.__name__,\n                     simple_dummy_resource.id),\n                    \"resource_type\": simple_dummy_resource.__class__.__name__\n                }\n            ]\n\n            simple_dummy_resource._achieve_absent_state(exec_logs)\n\n            self.assertEqual(exec_logs, expected_exec_logs)\n\n        test_when_resource_exists_but_policy_request_fails()\n        test_when_resource_exists_and_policy_request_succeeds()\n        test_when_resource_does_not_exist()\n        nsxt_base_resource.BASE_RESOURCES = init_base_resources\n\n    def test_get_sub_resources_class_of(self):\n        nested_dummy_resource = NestedDummyNSXTResource()\n\n        expected_values = [NestedDummyNSXTResource.SubDummyResource1,\n                           NestedDummyNSXTResource.SubDummyResource2,\n                           NestedDummyNSXTResource.SubDummyResource3]\n\n        observed_values = list(\n            nested_dummy_resource._get_sub_resources_class_of(\n                nested_dummy_resource.__class__))\n\n        self.assertCountEqual(expected_values, observed_values)\n\n    def test_fill_missing_resource_params(self):\n        simple_dummy_resource = SimpleDummyNSXTResource()\n\n        def test_simple():\n            def test_overwrite():\n                existing_params = {\n                    \"dummy\": \"dummy\"\n                }\n                resource_params = expected_resource_params = {\n                    \"dummy\": \"new_dummy\"\n                }\n                simple_dummy_resource._fill_missing_resource_params(\n                    existing_params, resource_params)\n\n                self.assertEqual(resource_params, expected_resource_params)\n\n            def test_missing():\n                existing_params = {\n                    \"dummy\": \"dummy\"\n                }\n                resource_params = {\n                    \"dummy1\": \"dummy1\"\n                }\n                expected_resource_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": \"dummy1\"\n                }\n                simple_dummy_resource._fill_missing_resource_params(\n                    existing_params, resource_params)\n\n                self.assertEqual(resource_params, expected_resource_params)\n\n            test_overwrite()\n            test_missing()\n\n        def test_with_dict():\n            def test_overwrite():\n                existing_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": {\n                        \"dummy2\": \"dummy2\"\n                    }\n                }\n                resource_params = expected_resource_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": {\n                        \"dummy2\": \"dummy3\"\n                    }\n                }\n                simple_dummy_resource._fill_missing_resource_params(\n                    existing_params, resource_params)\n\n                self.assertEqual(resource_params, expected_resource_params)\n\n            def test_missing():\n                existing_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": {\n                        \"dummy2\": \"dummy2\",\n                        \"dummy3\": {\n                            \"dummy4\": \"dummy4\"\n                        }\n                    },\n                    \"dummy5\": {\n                        \"dummy6\": \"dummy6\"\n                    }\n                }\n                resource_params = {\n                    \"dummy\": \"dummy1\",\n                    \"dummy1\": {\n                        \"dummy2\": \"dummy2\"\n                    }\n                }\n                expected_resource_params = {\n                    \"dummy\": \"dummy1\",\n                    \"dummy1\": {\n                        \"dummy2\": \"dummy2\",\n                        \"dummy3\": {\n                            \"dummy4\": \"dummy4\"\n                        }\n                    },\n                    \"dummy5\": {\n                        \"dummy6\": \"dummy6\"\n                    }\n                }\n                simple_dummy_resource._fill_missing_resource_params(\n                    existing_params, resource_params)\n\n                self.assertEqual(resource_params, expected_resource_params)\n\n            test_overwrite()\n            test_missing()\n\n        def test_with_list():\n            def test_overwrite():\n                existing_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": [\"dummy1\"]\n                }\n                resource_params = expected_resource_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": [\"dummy2\"]\n                }\n                simple_dummy_resource._fill_missing_resource_params(\n                    existing_params, resource_params)\n\n                self.assertEqual(resource_params, expected_resource_params)\n\n            def test_missing():\n                existing_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": [\"dummy1\"]\n                }\n                resource_params = {\n                    \"dummy\": \"dummy1\"\n                }\n                expected_resource_params = {\n                    \"dummy\": \"dummy1\",\n                    \"dummy1\": [\"dummy1\"]\n                }\n                simple_dummy_resource._fill_missing_resource_params(\n                    existing_params, resource_params)\n\n                self.assertEqual(resource_params, expected_resource_params)\n\n            test_overwrite()\n            test_missing()\n\n        def test_with_dict_and_list():\n            def test_overwrite():\n                existing_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": [\"dummy1\"],\n                    \"dummy2\": {\n                        \"dummy3\": [\"dummy3\"]\n                    }\n                }\n                resource_params = expected_resource_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": [\"dummy2\"],\n                    \"dummy2\": {\n                        \"dummy3\": [\"dummy4\"]\n                    }\n                }\n                simple_dummy_resource._fill_missing_resource_params(\n                    existing_params, resource_params)\n\n                self.assertEqual(resource_params, expected_resource_params)\n\n            def test_missing():\n                existing_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": [\"dummy1\"],\n                    \"dummy2\": {\n                        \"dummy3\": [\"dummy3\"]\n                    }\n                }\n                resource_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": [\"dummy2\"],\n                    \"dummy2\": {\n                        \"dummy4\": \"dummy4\"\n                    }\n                }\n                expected_resource_params = {\n                    \"dummy\": \"dummy\",\n                    \"dummy1\": [\"dummy2\"],\n                    \"dummy2\": {\n                        \"dummy3\": [\"dummy3\"],\n                        \"dummy4\": \"dummy4\"\n                    }\n                }\n                simple_dummy_resource._fill_missing_resource_params(\n                    existing_params, resource_params)\n\n                self.assertEqual(resource_params, expected_resource_params)\n\n            test_overwrite()\n            test_missing()\n\n        test_simple()\n        test_with_dict()\n        test_with_list()\n        test_with_dict_and_list()\n"
  },
  {
    "path": "tests/unit/plugins/module_utils/test_policy_communicator.py",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n#\n# Copyright 2018 VMware, Inc.\n# SPDX-License-Identifier: BSD-2-Clause OR GPL-3.0-only\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\n# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED.\n# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY\n# DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n# ON ANY THEORY OF LIABILITY,\n# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\n# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\nimport unittest\nimport json\nfrom unittest.mock import Mock, patch\n\nfrom ansible_collections.vmware.ansible_for_nsxt.plugins.module_utils.policy_communicator import PolicyCommunicator\nfrom ansible.module_utils.urls import open_url\nfrom ansible.module_utils.six.moves.urllib.error import HTTPError\n\n\nclass PolicyCommunicatorTestCase(unittest.TestCase):\n    def setUp(self):\n        self.policy_communicator = PolicyCommunicator.get_instance(\n            \"dummy\", \"dummy\", \"dummy\")\n\n    def test_get_instance_with_same_credentials(self):\n        pc1 = PolicyCommunicator.get_instance(\"dummy1\", \"dummy1\", \"dummy1\")\n        pc2 = PolicyCommunicator.get_instance(\"dummy1\", \"dummy1\", \"dummy1\")\n\n        self.assertEqual(pc1, pc2)\n\n    def test_get_instance_with_different_credentials(self):\n        pc1 = PolicyCommunicator.get_instance(\"dummy1\", \"dummy1\", \"dummy1\")\n        pc2 = PolicyCommunicator.get_instance(\"dummy2\", \"dummy2\", \"dummy2\")\n\n        self.assertNotEqual(pc1, pc2)\n\n    @patch(\"ansible_collections.vmware.ansible_for_nsxt.plugins.\"\n           \"module_utils.policy_communicator.open_url\")\n    def test_request_success_policy_response_with_success(self, mock_open_url):\n        pc = self.policy_communicator\n\n        expected_rc = 200\n        expected_response = '{\"dummy\": \"dummy\"}'\n\n        mock_response = Mock()\n        mock_response.getcode.return_value = expected_rc\n        mock_response.read.return_value.decode.return_value = expected_response\n        mock_open_url.return_value = mock_response\n\n        rc, response = pc.request(\"dummy\")\n\n        self.assertEqual(rc, 200)\n        self.assertEqual(response, json.loads(expected_response))\n\n    @patch(\"ansible_collections.vmware.ansible_for_nsxt.plugins.\"\n           \"module_utils.policy_communicator.open_url\")\n    def test_request_success_policy_response_with_none(self, mock_open_url):\n        pc = self.policy_communicator\n\n        expected_rc = 200\n        expected_response = None\n\n        mock_fp = Mock()\n        mock_fp.getcode.return_value = 200\n        mock_fp.read.return_value.decode.return_value = expected_response\n        mock_open_url.side_effect = HTTPError(\n            url=\"dummy\", code=200, msg=None, fp=mock_fp, hdrs=None)\n\n        rc, response = pc.request(\"dummy\")\n\n        self.assertEqual(rc, 200)\n        self.assertEqual(response, None)\n\n    @patch(\"ansible_collections.vmware.ansible_for_nsxt.plugins.\"\n           \"module_utils.policy_communicator.open_url\")\n    def test_request_success_policy_response_with_error(self, mock_open_url):\n        pc = self.policy_communicator\n\n        expected_rc = 200\n        expected_response = '{\"error_code\": \"5000212\"}'\n\n        mock_fp = Mock()\n        mock_fp.getcode.return_value = 200\n        mock_fp.read.return_value.decode.return_value = expected_response\n        mock_open_url.side_effect = HTTPError(\n            url=\"dummy\", code=\"dummy\", msg=None, fp=mock_fp, hdrs=None)\n\n        with self.assertRaises(Exception):\n            rc, response = pc.request(\"dummy\")\n\n    @patch(\"ansible_collections.vmware.ansible_for_nsxt.plugins.\"\n           \"module_utils.policy_communicator.open_url\")\n    def test_request_failure(self, mock_open_url):\n        pc = self.policy_communicator\n\n        mock_response = Mock()\n        mock_response.getcode.return_value = 400\n        mock_response.read.return_value.decode.return_value = (\n            '{\"dummy\": \"dummy\"}')\n        mock_open_url.return_value = mock_response\n\n        with self.assertRaises(Exception):\n            rc, response = pc.request(\"dummy\")\n"
  }
]