diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index b0aa351c..00000000
--- a/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-.tox/
-cloudinit.egg-info/
-*.pyc
-doc/build
-doc/source/api/
-ChangeLog
-AUTHORS
-cover/
diff --git a/HACKING.rst b/HACKING.rst
deleted file mode 100644
index def7bc22..00000000
--- a/HACKING.rst
+++ /dev/null
@@ -1,47 +0,0 @@
-=====================
-Hacking on cloud-init
-=====================
-
-To get changes into cloud-init, the process to follow is:
-
-* Fork from github, create a branch and make your changes
-
- - ``git clone https://github.com/openstack/cloud-init``
- - ``cd cloud-init``
- - ``echo hack``
-
-* Check test and code formatting / lint and address any issues:
-
- - ``tox``
-
-* Commit / ammend your changes (before review, make good commit messages with
- one line summary followed by empty line followed by expanded comments).
-
- - ``git commit``
-
-* Push to http://review.openstack.org:
-
- - ``git-review``
-
-* Before your changes can be accepted, you must sign the `Canonical
- Contributors License Agreement`_. Use 'Scott Moser' as the 'Project
- contact'. To check to see if you've done this before, look for your
- name in the `Canonical Contributor Agreement Team`_ on Launchpad.
-
-Then be patient and wait (or ping someone on cloud-init team).
-
-* `Core reviewers/maintainers`_
-
-Remember the more you are involved in the project the more beneficial it is
-for everyone involved (including yourself).
-
-**Contacting us:**
-
-Feel free to ping the folks listed above and/or join ``#cloud-init`` on
-`freenode`_ (`IRC`_) if you have any questions.
-
-.. _Core reviewers/maintainers: https://review.openstack.org/#/admin/groups/665,members
-.. _IRC: irc://chat.freenode.net/cloud-init
-.. _freenode: http://freenode.net/
-.. _Canonical Contributors License Agreement: http://www.ubuntu.com/legal/contributors
-.. _Canonical Contributor Agreement Team: https://launchpad.net/~contributor-agreement-canonical/+members#active
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 8a23b4d1..00000000
--- a/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-Copyright 2015 Canonical Ltd.
-
-This program is free software: you can redistribute it and/or modify it under
-the terms of the GNU General Public License version 3, as published by the
-Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
-SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License along with
-this program. If not, see
-
-Alternatively, this program may be used under the terms of the Apache License,
-Version 2.0, in which case the provisions of that license are applicable
-instead of those above. If you wish to allow use of your version of this
-program under the terms of the Apache License, Version 2.0 only, indicate
-your decision by deleting the provisions above and replace them with the notice
-and other provisions required by the Apache License, Version 2.0. If you do not
-delete the provisions above, a recipient may use your version of this file
-under the terms of either the GPLv3 or the Apache License, Version 2.0.
diff --git a/LICENSE-Apache2.0 b/LICENSE-Apache2.0
deleted file mode 100644
index d6456956..00000000
--- a/LICENSE-Apache2.0
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/LICENSE-GPLv3 b/LICENSE-GPLv3
deleted file mode 100644
index 94a9ed02..00000000
--- a/LICENSE-GPLv3
+++ /dev/null
@@ -1,674 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- Copyright (C)
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-.
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 23800499..00000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,8 +0,0 @@
-include AUTHORS
-include ChangeLog
-include README.rst
-exclude .gitignore
-exclude .gitreview
-
-global-exclude *.pyc
-
diff --git a/README b/README
new file mode 100644
index 00000000..eb99bcd9
--- /dev/null
+++ b/README
@@ -0,0 +1,9 @@
+This project is no longer maintained.
+
+The contents of this repository are still available in the Git
+source code management system. To see the contents of this
+repository before it reached its end of life, please check out the
+previous commit with "git checkout HEAD^1".
+
+For any further questions, please email
+openstack-discuss@lists.openstack.org.
diff --git a/README.rst b/README.rst
deleted file mode 100644
index 59e6f766..00000000
--- a/README.rst
+++ /dev/null
@@ -1,50 +0,0 @@
-Cloud-init
-==========
-
-*Cloud-init initializes systems for cloud environments.*
-
-Join us
--------
-
-- http://launchpad.net/cloud-init
-
-
-Bugs
-----
-Bug reports should be opened at
- https://bugs.launchpad.net/cloud-init/+filebug
-
-On Ubuntu Systems, you can file bugs with:
-
-::
-
- $ ubuntu-bug cloud-init
-
-Testing and requirements
-------------------------
-
-Requirements
-~~~~~~~~~~~~
-
-TBD
-
-Tox.ini
-~~~~~~~
-
-Our ``tox.ini`` file describes several test environments that allow to test
-cloud-init with different python versions and sets of requirements installed.
-Please refer to the `tox`_ documentation to understand how to make these test
-environments work for you.
-
-Developer documentation
------------------------
-
-We also have sphinx documentation in ``docs/source``.
-
-*To build it, run:*
-
-::
-
- $ python setup.py build_sphinx
-
-.. _tox: http://tox.testrun.org/
diff --git a/cloudinit/__init__.py b/cloudinit/__init__.py
deleted file mode 100644
index 20b32a23..00000000
--- a/cloudinit/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
diff --git a/cloudinit/config/__init__.py b/cloudinit/config/__init__.py
deleted file mode 100644
index 20b32a23..00000000
--- a/cloudinit/config/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
diff --git a/cloudinit/exceptions.py b/cloudinit/exceptions.py
deleted file mode 100644
index 677cd236..00000000
--- a/cloudinit/exceptions.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-
-class CloudInitError(Exception):
- pass
diff --git a/cloudinit/logging.py b/cloudinit/logging.py
deleted file mode 100644
index a1e52840..00000000
--- a/cloudinit/logging.py
+++ /dev/null
@@ -1,113 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-from __future__ import absolute_import
-
-import logging
-import sys
-
-_BASE = __name__.split(".", 1)[0]
-
-# Add a BLATHER level, this matches the multiprocessing utils.py module (and
-# kazoo and others) that declares a similar level, this level is for
-# information that is even lower level than regular DEBUG and gives out so
-# much runtime information that it is only useful by low-level/certain users...
-BLATHER = 5
-
-# Copy over *select* attributes to make it easy to use this module.
-CRITICAL = logging.CRITICAL
-DEBUG = logging.DEBUG
-ERROR = logging.ERROR
-FATAL = logging.FATAL
-INFO = logging.INFO
-NOTSET = logging.NOTSET
-WARN = logging.WARN
-WARNING = logging.WARNING
-
-
-class _BlatherLoggerAdapter(logging.LoggerAdapter):
-
- def blather(self, msg, *args, **kwargs):
- """Delegate a blather call to the underlying logger."""
- self.log(BLATHER, msg, *args, **kwargs)
-
- def warn(self, msg, *args, **kwargs):
- """Delegate a warning call to the underlying logger."""
- self.warning(msg, *args, **kwargs)
-
-
-# TODO(harlowja): we should remove when we no longer have to support 2.6...
-if sys.version_info[0:2] == (2, 6): # pragma: nocover
- from logutils.dictconfig import dictConfig
-
- class _FixedBlatherLoggerAdapter(_BlatherLoggerAdapter):
- """Ensures isEnabledFor() exists on adapters that are created."""
-
- def isEnabledFor(self, level):
- return self.logger.isEnabledFor(level)
-
- _BlatherLoggerAdapter = _FixedBlatherLoggerAdapter
-
- # Taken from python2.7 (same in python3.4)...
- class _NullHandler(logging.Handler):
- """This handler does nothing.
-
- It's intended to be used to avoid the
- "No handlers could be found for logger XXX" one-off warning. This is
- important for library code, which may contain code to log events. If a
- user of the library does not configure logging, the one-off warning
- might be produced; to avoid this, the library developer simply needs
- to instantiate a _NullHandler and add it to the top-level logger of the
- library module or package.
- """
-
- def handle(self, record):
- """Stub."""
-
- def emit(self, record):
- """Stub."""
-
- def createLock(self):
- self.lock = None
-
-else:
- from logging.config import dictConfig
- _NullHandler = logging.NullHandler
-
-
-def getLogger(name=_BASE, extra=None):
- logger = logging.getLogger(name)
- if not logger.handlers:
- logger.addHandler(_NullHandler())
- return _BlatherLoggerAdapter(logger, extra=extra)
-
-
-def configure_logging(log_to_console=False):
- logging_config = {
- 'version': 1,
- 'disable_existing_loggers': False,
- 'formatters': {
- 'standard': {
- 'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s',
- },
- },
- 'handlers': {
- 'console': {
- 'level': 'INFO',
- 'class': 'logging.StreamHandler',
- 'formatter': 'standard',
- },
- },
- 'loggers': {
- '': {
- 'handlers': [],
- 'level': 'DEBUG',
- 'propagate': True,
- },
- },
- }
- if log_to_console:
- logging_config['loggers']['']['handlers'].append('console')
- dictConfig(logging_config)
diff --git a/cloudinit/osys/__init__.py b/cloudinit/osys/__init__.py
deleted file mode 100644
index 20b32a23..00000000
--- a/cloudinit/osys/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
diff --git a/cloudinit/osys/base.py b/cloudinit/osys/base.py
deleted file mode 100644
index 0a468d89..00000000
--- a/cloudinit/osys/base.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright 2015 Cloudbase Solutions Srl
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import abc
-import importlib
-import platform
-
-import six
-
-
-__all__ = (
- 'get_osutils',
- 'OSUtils',
-)
-
-
-def get_osutils():
- """Obtain the OS utils object for the underlying platform."""
- name, _, _ = platform.linux_distribution()
- if not name:
- name = platform.system()
-
- name = name.lower()
- location = "cloudinit.osys.{0}.base".format(name)
- module = importlib.import_module(location)
- return module.OSUtils
-
-
-@six.add_metaclass(abc.ABCMeta)
-class OSUtils(object):
- """Base class for an OS utils namespace.
-
- This base class provides a couple of hooks which needs to be
- implemented by subclasses, for each particular OS and distro.
- """
-
- name = None
-
- @abc.abstractproperty
- def network(self):
- """Get the network object for the underlying platform."""
-
- @abc.abstractproperty
- def filesystem(self):
- """Get the filesystem object for the underlying platform."""
-
- @abc.abstractproperty
- def users(self):
- """Get the users object for the underlying platform."""
-
- @abc.abstractproperty
- def general(self):
- """Get the general object for the underlying platform."""
-
- @abc.abstractproperty
- def user_class(self):
- """Get the user class specific to this operating system."""
-
- @abc.abstractproperty
- def route_class(self):
- """Get the route class specific to this operating system."""
-
- @abc.abstractproperty
- def interface_class(self):
- """Get the interface class specific to this operating system."""
diff --git a/cloudinit/osys/general.py b/cloudinit/osys/general.py
deleted file mode 100644
index 8553ccb8..00000000
--- a/cloudinit/osys/general.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright 2015 Cloudbase Solutions Srl
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import abc
-
-import six
-
-
-@six.add_metaclass(abc.ABCMeta)
-class General(object):
- """Base class for the general namespace.
-
- This class should contain common functions between all OSes,
- which can't be grouped in a domain-specific namespace.
- """
-
- @abc.abstractmethod
- def set_timezone(self, timezone):
- """Change the timezone for the underlying platform.
-
- The `timezone` parameter should be a TZID timezone format,
- e.g. 'Africa/Mogadishu'
- """
-
- @abc.abstractmethod
- def set_locale(self, locale):
- """Change the locale for the underlying platform."""
-
- @abc.abstractmethod
- def reboot(self):
- pass
diff --git a/cloudinit/osys/network.py b/cloudinit/osys/network.py
deleted file mode 100644
index ac357fef..00000000
--- a/cloudinit/osys/network.py
+++ /dev/null
@@ -1,156 +0,0 @@
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright 2015 Cloudbase Solutions Srl
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import abc
-
-import six
-
-from cloudinit import util
-
-
-__all__ = (
- 'Network',
- 'Route',
- 'Interface',
-)
-
-
-@six.add_metaclass(abc.ABCMeta)
-class Network(object):
- """Base network class for network related utilities."""
-
- @abc.abstractmethod
- def routes(self):
- """Get the list of the available routes."""
-
- @abc.abstractmethod
- def default_gateway(self):
- """Get the default gateway, as a route object."""
-
- @abc.abstractmethod
- def interfaces(self):
- """Get the list of the available interfaces."""
-
- @abc.abstractmethod
- def hosts(self):
- """Get the list of the available hosts."""
-
- @abc.abstractmethod
- def set_hostname(self, hostname):
- """Change the host name of the instance."""
-
- @abc.abstractmethod
- def set_static_network_config(self, adapter_name, address, netmask,
- broadcast, gateway, dnsnameservers):
- """Configure a new static network."""
-
-
-@six.add_metaclass(abc.ABCMeta)
-class Route(object):
- """Base class for routes."""
-
- def __init__(self, destination, gateway, netmask,
- interface, metric,
- flags=None, refs=None, use=None, expire=None):
- self.destination = destination
- self.gateway = gateway
- self.netmask = netmask
- self.interface = interface
- self.metric = metric
- self.flags = flags
- self.refs = refs
- self.use = use
- self.expire = expire
-
- def __repr__(self):
- return ("Route(destination={!r}, gateway={!r}, netmask={!r})"
- .format(self.destination, self.gateway, self.netmask))
-
- @abc.abstractproperty
- def is_static(self):
- """Check if this route is static."""
-
- @util.abstractclassmethod
- def add(cls, route):
- """Add a new route in the underlying OS.
-
- The `route` parameter should be an instance of :class:`Route`.
- """
-
- @util.abstractclassmethod
- def delete(cls, route):
- """Delete a route from the underlying OS.
-
- The `route` parameter should be an instance of :class:`Route`.
- """
-
-
-@six.add_metaclass(abc.ABCMeta)
-class Interface(object):
- """Base class reprensenting an interface.
-
- It provides both attributes for retrieving interface information,
- as well as methods for modifying the state of a route, such
- as activating or deactivating it.
- """
-
- def __init__(self, name, mac, index=None, mtu=None,
- dhcp_server=None, dhcp_enabled=None):
- self._mtu = mtu
-
- self.name = name
- self.index = index
- self.mac = mac
- self.dhcp_server = dhcp_server
- self.dhcp_enabled = dhcp_enabled
-
- def __eq__(self, other):
- return (self.mac == other.mac and
- self.name == other.name and
- self.index == other.index)
-
- @abc.abstractmethod
- def _change_mtu(self, value):
- """Change the mtu for the underlying interface."""
-
- @util.abstractclassmethod
- def from_name(cls, name):
- """Get an instance of :class:`Interface` from an interface name.
-
- E.g. this should retrieve the 'eth0' interface::
-
- >>> Interface.from_name('eth0')
- """
-
- @abc.abstractmethod
- def up(self):
- """Activate the current interface."""
-
- @abc.abstractmethod
- def down(self):
- """Deactivate the current interface."""
-
- @abc.abstractmethod
- def is_up(self):
- """Check if this interface is activated."""
-
- @property
- def mtu(self):
- return self._mtu
-
- @mtu.setter
- def mtu(self, value):
- self._change_mtu(value)
- self._mtu = value
diff --git a/cloudinit/osys/users.py b/cloudinit/osys/users.py
deleted file mode 100644
index 24d90ab7..00000000
--- a/cloudinit/osys/users.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright 2015 Cloudbase Solutions Srl
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import abc
-
-import six
-
-from cloudinit import util
-
-
-@six.add_metaclass(abc.ABCMeta)
-class Users(object):
- """Base class for user related operations."""
-
- @abc.abstractmethod
- def groups(self):
- """Get a list of the groups available in the system."""
-
- @abc.abstractmethod
- def users(self):
- """Get a list of the users available in the system."""
-
-
-@six.add_metaclass(abc.ABCMeta)
-class Group(object):
- """Base class for user groups."""
-
- @util.abstractclassmethod
- def create(cls, group_name):
- """Create a new group with the given name."""
-
- @abc.abstractmethod
- def add(self, member):
- """Add a new member to this group."""
-
-
-@six.add_metaclass(abc.ABCMeta)
-class User(object):
- """Base class for an user."""
-
- @classmethod
- def create(cls, username, password, **kwargs):
- """Create a new user."""
-
- @abc.abstractmethod
- def home(self):
- """Get the user's home directory."""
-
- @abc.abstractmethod
- def ssh_keys(self):
- """Get the ssh keys for this user."""
-
- @abc.abstractmethod
- def change_password(self, password):
- """Change the password for this user."""
diff --git a/cloudinit/osys/windows/__init__.py b/cloudinit/osys/windows/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/cloudinit/osys/windows/base.py b/cloudinit/osys/windows/base.py
deleted file mode 100644
index 65ea3ace..00000000
--- a/cloudinit/osys/windows/base.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-from cloudinit.osys import base
-from cloudinit.osys.windows import general as general_module
-from cloudinit.osys.windows import network as network_module
-
-
-__all__ = ('OSUtils', )
-
-
-class OSUtils(base.OSUtils):
- """The OS utils namespace for the Windows platform."""
-
- name = "windows"
-
- network = network_module.Network()
- general = general_module.General()
- route_class = network_module.Route
-
- # These aren't yet implemented, use `None` for them
- # so that we could instantiate the class.
- filesystem = user_class = users = None
- interface_class = None
diff --git a/cloudinit/osys/windows/general.py b/cloudinit/osys/windows/general.py
deleted file mode 100644
index db92049c..00000000
--- a/cloudinit/osys/windows/general.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-"""General utilities for Windows platform."""
-
-import ctypes
-
-from cloudinit import exceptions
-from cloudinit.osys import general
-from cloudinit.osys.windows.util import kernel32
-
-
-class General(general.General):
- """General utilities namespace for Windows."""
-
- @staticmethod
- def check_os_version(major, minor, build=0):
- """Check if this OS version is equal or higher than (major, minor)"""
-
- version_info = kernel32.Win32_OSVERSIONINFOEX_W()
- version_info.dwOSVersionInfoSize = ctypes.sizeof(
- kernel32.Win32_OSVERSIONINFOEX_W)
-
- version_info.dwMajorVersion = major
- version_info.dwMinorVersion = minor
- version_info.dwBuildNumber = build
-
- mask = 0
- for type_mask in [kernel32.VER_MAJORVERSION,
- kernel32.VER_MINORVERSION,
- kernel32.VER_BUILDNUMBER]:
- mask = kernel32.VerSetConditionMask(mask, type_mask,
- kernel32.VER_GREATER_EQUAL)
-
- type_mask = (kernel32.VER_MAJORVERSION |
- kernel32.VER_MINORVERSION |
- kernel32.VER_BUILDNUMBER)
- ret_val = kernel32.VerifyVersionInfoW(ctypes.byref(version_info),
- type_mask, mask)
- if ret_val:
- return True
- else:
- err = kernel32.GetLastError()
- if err == kernel32.ERROR_OLD_WIN_VERSION:
- return False
- else:
- raise exceptions.CloudInitError(
- "VerifyVersionInfo failed with error: %s" % err)
-
- def reboot(self):
- raise NotImplementedError
-
- def set_locale(self, locale):
- raise NotImplementedError
-
- def set_timezone(self, timezone):
- raise NotImplementedError
diff --git a/cloudinit/osys/windows/network.py b/cloudinit/osys/windows/network.py
deleted file mode 100644
index 43ac1f25..00000000
--- a/cloudinit/osys/windows/network.py
+++ /dev/null
@@ -1,209 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-"""Network utilities for Windows."""
-
-import contextlib
-import ctypes
-from ctypes import wintypes
-import logging
-import subprocess
-
-from six.moves import urllib_parse
-
-from cloudinit import exceptions
-from cloudinit.osys import base
-from cloudinit.osys import network
-from cloudinit.osys.windows.util import iphlpapi
-from cloudinit.osys.windows.util import kernel32
-from cloudinit.osys.windows.util import ws2_32
-from cloudinit import url_helper
-
-
-MIB_IPPROTO_NETMGMT = 3
-_FW_IP_PROTOCOL_TCP = 6
-_FW_IP_PROTOCOL_UDP = 17
-_FW_SCOPE_ALL = 0
-_PROTOCOL_TCP = "TCP"
-_PROTOCOL_UDP = "UDP"
-_ERROR_FILE_NOT_FOUND = 2
-_ComputerNamePhysicalDnsHostname = 5
-_MAX_URL_CHECK_RETRIES = 3
-LOG = logging.getLogger(__name__)
-
-
-def _heap_alloc(heap, size):
- table_mem = kernel32.HeapAlloc(heap, 0, ctypes.c_size_t(size.value))
- if not table_mem:
- raise exceptions.CloudInitError(
- 'Unable to allocate memory for the IP forward table')
- return table_mem
-
-
-def _check_url(url, retries_count=_MAX_URL_CHECK_RETRIES):
- LOG.debug("Testing url: %s", url)
- try:
- url_helper.read_url(url, retries=retries_count)
- return True
- except url_helper.UrlError:
- return False
-
-
-class Network(network.Network):
- """Network namespace object tailored for the Windows platform."""
-
- @staticmethod
- @contextlib.contextmanager
- def _get_forward_table():
- heap = kernel32.GetProcessHeap()
- forward_table_size = ctypes.sizeof(iphlpapi.Win32_MIB_IPFORWARDTABLE)
- size = wintypes.ULONG(forward_table_size)
- table_mem = _heap_alloc(heap, size)
-
- p_forward_table = ctypes.cast(
- table_mem, ctypes.POINTER(iphlpapi.Win32_MIB_IPFORWARDTABLE))
-
- try:
- err = iphlpapi.GetIpForwardTable(p_forward_table,
- ctypes.byref(size), 0)
- if err == iphlpapi.ERROR_INSUFFICIENT_BUFFER:
- kernel32.HeapFree(heap, 0, p_forward_table)
- table_mem = _heap_alloc(heap, size)
- p_forward_table = ctypes.cast(
- table_mem,
- ctypes.POINTER(iphlpapi.Win32_MIB_IPFORWARDTABLE))
- err = iphlpapi.GetIpForwardTable(p_forward_table,
- ctypes.byref(size), 0)
-
- if err and err != kernel32.ERROR_NO_DATA:
- raise exceptions.CloudInitError(
- 'Unable to get IP forward table. Error: %s' % err)
-
- yield p_forward_table
- finally:
- kernel32.HeapFree(heap, 0, p_forward_table)
-
- def routes(self):
- """Get a collection of the available routes."""
- routing_table = []
- with self._get_forward_table() as p_forward_table:
- forward_table = p_forward_table.contents
- table = ctypes.cast(
- ctypes.addressof(forward_table.table),
- ctypes.POINTER(iphlpapi.Win32_MIB_IPFORWARDROW *
- forward_table.dwNumEntries)).contents
-
- for row in table:
- destination = ws2_32.Ws2_32.inet_ntoa(
- row.dwForwardDest).decode()
- netmask = ws2_32.Ws2_32.inet_ntoa(
- row.dwForwardMask).decode()
- gateway = ws2_32.Ws2_32.inet_ntoa(
- row.dwForwardNextHop).decode()
- index = row.dwForwardIfIndex
- flags = row.dwForwardProto
- metric = row.dwForwardMetric1
- route = Route(destination=destination,
- gateway=gateway,
- netmask=netmask,
- interface=index,
- metric=metric,
- flags=flags)
- routing_table.append(route)
-
- return routing_table
-
- def default_gateway(self):
- """Get the default gateway.
-
- This will actually return a :class:`Route` instance. The gateway
- can be accessed with the :attr:`gateway` attribute.
- """
- return next((r for r in self.routes() if r.destination == '0.0.0.0'),
- None)
-
- def set_metadata_ip_route(self, metadata_url):
- """Set a network route if the given metadata url can't be accessed.
-
- This is a workaround for
- https://bugs.launchpad.net/quantum/+bug/1174657.
- """
- osutils = base.get_osutils()
-
- if osutils.general.check_os_version(6, 0):
- # 169.254.x.x addresses are not getting routed starting from
- # Windows Vista / 2008
- metadata_netloc = urllib_parse.urlparse(metadata_url).netloc
- metadata_host = metadata_netloc.split(':')[0]
-
- if not metadata_host.startswith("169.254."):
- return
-
- routes = self.routes()
- exists_route = any(route.destination == metadata_host
- for route in routes)
- if not exists_route and not _check_url(metadata_url):
- default_gateway = self.default_gateway()
- if default_gateway:
- try:
- LOG.debug('Setting gateway for host: %s',
- metadata_host)
- route = Route(
- destination=metadata_host,
- netmask="255.255.255.255",
- gateway=default_gateway.gateway,
- interface=None, metric=None)
- Route.add(route)
- except Exception as ex:
- # Ignore it
- LOG.exception(ex)
-
- # These are not required by the Windows version for now,
- # but we provide them as noop version.
- def hosts(self):
- """Grab the content of the hosts file."""
- raise NotImplementedError
-
- def interfaces(self):
- raise NotImplementedError
-
- def set_hostname(self, hostname):
- raise NotImplementedError
-
- def set_static_network_config(self, adapter_name, address, netmask,
- broadcast, gateway, dnsnameservers):
- raise NotImplementedError
-
-
-class Route(network.Route):
- """Windows route class."""
-
- @property
- def is_static(self):
- return self.flags == MIB_IPPROTO_NETMGMT
-
- @classmethod
- def add(cls, route):
- """Add a new route in the underlying OS.
-
- The function should expect an instance of :class:`Route`.
- """
- args = ['ROUTE', 'ADD',
- route.destination,
- 'MASK', route.netmask, route.gateway]
- popen = subprocess.Popen(args, shell=False,
- stderr=subprocess.PIPE)
- _, stderr = popen.communicate()
- if popen.returncode or stderr:
- # Cannot use the return value to determine the outcome
- raise exceptions.CloudInitError('Unable to add route: %s' % stderr)
-
- @classmethod
- def delete(cls, _):
- """Delete a route from the underlying OS.
-
- This function should expect an instance of :class:`Route`.
- """
- raise NotImplementedError
diff --git a/cloudinit/osys/windows/util/__init__.py b/cloudinit/osys/windows/util/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/cloudinit/osys/windows/util/iphlpapi.py b/cloudinit/osys/windows/util/iphlpapi.py
deleted file mode 100644
index e1301860..00000000
--- a/cloudinit/osys/windows/util/iphlpapi.py
+++ /dev/null
@@ -1,210 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import ctypes
-
-from ctypes import windll
-from ctypes import wintypes
-
-from cloudinit.osys.windows.util import kernel32
-from cloudinit.osys.windows.util import ws2_32
-
-ERROR_INSUFFICIENT_BUFFER = 122
-
-MAX_ADAPTER_NAME_LENGTH = 256
-MAX_ADAPTER_DESCRIPTION_LENGTH = 128
-MAX_ADAPTER_ADDRESS_LENGTH = 8
-
-# Do not return IPv6 anycast addresses.
-GAA_FLAG_SKIP_ANYCAST = 2
-GAA_FLAG_SKIP_MULTICAST = 4
-
-IP_ADAPTER_DHCP_ENABLED = 4
-IP_ADAPTER_IPV4_ENABLED = 0x80
-IP_ADAPTER_IPV6_ENABLED = 0x0100
-
-MAX_DHCPV6_DUID_LENGTH = 130
-
-IF_TYPE_ETHERNET_CSMACD = 6
-IF_TYPE_SOFTWARE_LOOPBACK = 24
-IF_TYPE_IEEE80211 = 71
-IF_TYPE_TUNNEL = 131
-
-IP_ADAPTER_ADDRESSES_SIZE_2003 = 144
-
-
-class SOCKET_ADDRESS(ctypes.Structure):
- _fields_ = [
- ('lpSockaddr', ctypes.POINTER(ws2_32.SOCKADDR)),
- ('iSockaddrLength', wintypes.INT),
- ]
-
-
-class IP_ADAPTER_ADDRESSES_Struct1(ctypes.Structure):
- _fields_ = [
- ('Length', wintypes.ULONG),
- ('IfIndex', wintypes.DWORD),
- ]
-
-
-class IP_ADAPTER_ADDRESSES_Union1(ctypes.Union):
- _fields_ = [
- ('Alignment', wintypes.ULARGE_INTEGER),
- ('Struct1', IP_ADAPTER_ADDRESSES_Struct1),
- ]
-
-
-class IP_ADAPTER_UNICAST_ADDRESS(ctypes.Structure):
- _fields_ = [
- ('Union1', IP_ADAPTER_ADDRESSES_Union1),
- ('Next', wintypes.LPVOID),
- ('Address', SOCKET_ADDRESS),
- ('PrefixOrigin', wintypes.DWORD),
- ('SuffixOrigin', wintypes.DWORD),
- ('DadState', wintypes.DWORD),
- ('ValidLifetime', wintypes.ULONG),
- ('PreferredLifetime', wintypes.ULONG),
- ('LeaseLifetime', wintypes.ULONG),
- ]
-
-
-class IP_ADAPTER_DNS_SERVER_ADDRESS_Struct1(ctypes.Structure):
- _fields_ = [
- ('Length', wintypes.ULONG),
- ('Reserved', wintypes.DWORD),
- ]
-
-
-class IP_ADAPTER_DNS_SERVER_ADDRESS_Union1(ctypes.Union):
- _fields_ = [
- ('Alignment', wintypes.ULARGE_INTEGER),
- ('Struct1', IP_ADAPTER_DNS_SERVER_ADDRESS_Struct1),
- ]
-
-
-class IP_ADAPTER_DNS_SERVER_ADDRESS(ctypes.Structure):
- _fields_ = [
- ('Union1', IP_ADAPTER_DNS_SERVER_ADDRESS_Union1),
- ('Next', wintypes.LPVOID),
- ('Address', SOCKET_ADDRESS),
- ]
-
-
-class IP_ADAPTER_PREFIX_Struct1(ctypes.Structure):
- _fields_ = [
- ('Length', wintypes.ULONG),
- ('Flags', wintypes.DWORD),
- ]
-
-
-class IP_ADAPTER_PREFIX_Union1(ctypes.Union):
- _fields_ = [
- ('Alignment', wintypes.ULARGE_INTEGER),
- ('Struct1', IP_ADAPTER_PREFIX_Struct1),
- ]
-
-
-class IP_ADAPTER_PREFIX(ctypes.Structure):
- _fields_ = [
- ('Union1', IP_ADAPTER_PREFIX_Union1),
- ('Next', wintypes.LPVOID),
- ('Address', SOCKET_ADDRESS),
- ('PrefixLength', wintypes.ULONG),
- ]
-
-
-class NET_LUID_LH(ctypes.Union):
- _fields_ = [
- ('Value', wintypes.ULARGE_INTEGER),
- ('Info', wintypes.ULARGE_INTEGER),
- ]
-
-
-class IP_ADAPTER_ADDRESSES(ctypes.Structure):
- _fields_ = [
- ('Union1', IP_ADAPTER_ADDRESSES_Union1),
- ('Next', wintypes.LPVOID),
- ('AdapterName', ctypes.c_char_p),
- ('FirstUnicastAddress',
- ctypes.POINTER(IP_ADAPTER_UNICAST_ADDRESS)),
- ('FirstAnycastAddress',
- ctypes.POINTER(IP_ADAPTER_DNS_SERVER_ADDRESS)),
- ('FirstMulticastAddress',
- ctypes.POINTER(IP_ADAPTER_DNS_SERVER_ADDRESS)),
- ('FirstDnsServerAddress',
- ctypes.POINTER(IP_ADAPTER_DNS_SERVER_ADDRESS)),
- ('DnsSuffix', wintypes.LPWSTR),
- ('Description', wintypes.LPWSTR),
- ('FriendlyName', wintypes.LPWSTR),
- ('PhysicalAddress', ctypes.c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH),
- ('PhysicalAddressLength', wintypes.DWORD),
- ('Flags', wintypes.DWORD),
- ('Mtu', wintypes.DWORD),
- ('IfType', wintypes.DWORD),
- ('OperStatus', wintypes.DWORD),
- ('Ipv6IfIndex', wintypes.DWORD),
- ('ZoneIndices', wintypes.DWORD * 16),
- ('FirstPrefix', ctypes.POINTER(IP_ADAPTER_PREFIX)),
- # kernel >= 6.0
- ('TransmitLinkSpeed', wintypes.ULARGE_INTEGER),
- ('ReceiveLinkSpeed', wintypes.ULARGE_INTEGER),
- ('FirstWinsServerAddress',
- ctypes.POINTER(IP_ADAPTER_DNS_SERVER_ADDRESS)),
- ('FirstGatewayAddress',
- ctypes.POINTER(IP_ADAPTER_DNS_SERVER_ADDRESS)),
- ('Ipv4Metric', wintypes.ULONG),
- ('Ipv6Metric', wintypes.ULONG),
- ('Luid', NET_LUID_LH),
- ('Dhcpv4Server', SOCKET_ADDRESS),
- ('CompartmentId', wintypes.DWORD),
- ('NetworkGuid', kernel32.GUID),
- ('ConnectionType', wintypes.DWORD),
- ('TunnelType', wintypes.DWORD),
- ('Dhcpv6Server', SOCKET_ADDRESS),
- ('Dhcpv6ClientDuid', ctypes.c_ubyte * MAX_DHCPV6_DUID_LENGTH),
- ('Dhcpv6ClientDuidLength', wintypes.ULONG),
- ('Dhcpv6Iaid', wintypes.ULONG),
- ]
-
-
-class Win32_MIB_IPFORWARDROW(ctypes.Structure):
- _fields_ = [
- ('dwForwardDest', wintypes.DWORD),
- ('dwForwardMask', wintypes.DWORD),
- ('dwForwardPolicy', wintypes.DWORD),
- ('dwForwardNextHop', wintypes.DWORD),
- ('dwForwardIfIndex', wintypes.DWORD),
- ('dwForwardType', wintypes.DWORD),
- ('dwForwardProto', wintypes.DWORD),
- ('dwForwardAge', wintypes.DWORD),
- ('dwForwardNextHopAS', wintypes.DWORD),
- ('dwForwardMetric1', wintypes.DWORD),
- ('dwForwardMetric2', wintypes.DWORD),
- ('dwForwardMetric3', wintypes.DWORD),
- ('dwForwardMetric4', wintypes.DWORD),
- ('dwForwardMetric5', wintypes.DWORD)
- ]
-
-
-class Win32_MIB_IPFORWARDTABLE(ctypes.Structure):
- _fields_ = [
- ('dwNumEntries', wintypes.DWORD),
- ('table', Win32_MIB_IPFORWARDROW * 1)
- ]
-
-
-GetAdaptersAddresses = windll.Iphlpapi.GetAdaptersAddresses
-GetAdaptersAddresses.argtypes = [
- wintypes.ULONG, wintypes.ULONG, wintypes.LPVOID,
- ctypes.POINTER(IP_ADAPTER_ADDRESSES),
- ctypes.POINTER(wintypes.ULONG)]
-GetAdaptersAddresses.restype = wintypes.ULONG
-
-GetIpForwardTable = windll.Iphlpapi.GetIpForwardTable
-GetIpForwardTable.argtypes = [
- ctypes.POINTER(Win32_MIB_IPFORWARDTABLE),
- ctypes.POINTER(wintypes.ULONG),
- wintypes.BOOL]
-GetIpForwardTable.restype = wintypes.DWORD
diff --git a/cloudinit/osys/windows/util/kernel32.py b/cloudinit/osys/windows/util/kernel32.py
deleted file mode 100644
index c03b9e87..00000000
--- a/cloudinit/osys/windows/util/kernel32.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import ctypes
-from ctypes import windll
-from ctypes import wintypes
-
-ERROR_BUFFER_OVERFLOW = 111
-ERROR_NO_DATA = 232
-
-
-class GUID(ctypes.Structure):
- _fields_ = [
- ("data1", wintypes.DWORD),
- ("data2", wintypes.WORD),
- ("data3", wintypes.WORD),
- ("data4", wintypes.BYTE * 8)]
-
- def __init__(self, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8):
- self.data1 = l
- self.data2 = w1
- self.data3 = w2
- self.data4[0] = b1
- self.data4[1] = b2
- self.data4[2] = b3
- self.data4[3] = b4
- self.data4[4] = b5
- self.data4[5] = b6
- self.data4[6] = b7
- self.data4[7] = b8
-
-
-class Win32_OSVERSIONINFOEX_W(ctypes.Structure):
- _fields_ = [
- ('dwOSVersionInfoSize', wintypes.DWORD),
- ('dwMajorVersion', wintypes.DWORD),
- ('dwMinorVersion', wintypes.DWORD),
- ('dwBuildNumber', wintypes.DWORD),
- ('dwPlatformId', wintypes.DWORD),
- ('szCSDVersion', wintypes.WCHAR * 128),
- ('wServicePackMajor', wintypes.DWORD),
- ('wServicePackMinor', wintypes.DWORD),
- ('wSuiteMask', wintypes.DWORD),
- ('wProductType', wintypes.BYTE),
- ('wReserved', wintypes.BYTE)
- ]
-
-
-GetLastError = windll.kernel32.GetLastError
-
-GetProcessHeap = windll.kernel32.GetProcessHeap
-GetProcessHeap.argtypes = []
-GetProcessHeap.restype = wintypes.HANDLE
-
-HeapAlloc = windll.kernel32.HeapAlloc
-# Note: wintypes.ULONG must be replaced with a 64 bit variable on x64
-HeapAlloc.argtypes = [wintypes.HANDLE, wintypes.DWORD, wintypes.ULONG]
-HeapAlloc.restype = wintypes.LPVOID
-
-HeapFree = windll.kernel32.HeapFree
-HeapFree.argtypes = [wintypes.HANDLE, wintypes.DWORD, wintypes.LPVOID]
-HeapFree.restype = wintypes.BOOL
-
-SetComputerNameExW = windll.kernel32.SetComputerNameExW
-
-VerifyVersionInfoW = windll.kernel32.VerifyVersionInfoW
-VerSetConditionMask = windll.kernel32.VerSetConditionMask
-
-VerifyVersionInfoW.argtypes = [
- ctypes.POINTER(Win32_OSVERSIONINFOEX_W),
- wintypes.DWORD, wintypes.ULARGE_INTEGER]
-VerifyVersionInfoW.restype = wintypes.BOOL
-
-VerSetConditionMask.argtypes = [wintypes.ULARGE_INTEGER,
- wintypes.DWORD,
- wintypes.BYTE]
-VerSetConditionMask.restype = wintypes.ULARGE_INTEGER
-
-ERROR_OLD_WIN_VERSION = 1150
-VER_MAJORVERSION = 1
-VER_MINORVERSION = 2
-VER_BUILDNUMBER = 4
-VER_GREATER_EQUAL = 3
diff --git a/cloudinit/osys/windows/util/ws2_32.py b/cloudinit/osys/windows/util/ws2_32.py
deleted file mode 100644
index 890e1cd6..00000000
--- a/cloudinit/osys/windows/util/ws2_32.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import ctypes
-from ctypes import windll
-from ctypes import wintypes
-
-AF_UNSPEC = 0
-AF_INET = 2
-AF_INET6 = 23
-
-VERSION_2_2 = (2 << 8) + 2
-
-
-class SOCKADDR(ctypes.Structure):
- _fields_ = [
- ('sa_family', wintypes.USHORT),
- ('sa_data', ctypes.c_char * 14),
- ]
-
-
-class WSADATA(ctypes.Structure):
- _fields_ = [
- ('opaque_data', wintypes.BYTE * 400),
- ]
-
-
-WSAGetLastError = windll.Ws2_32.WSAGetLastError
-WSAGetLastError.argtypes = []
-WSAGetLastError.restype = wintypes.INT
-
-WSAStartup = windll.Ws2_32.WSAStartup
-WSAStartup.argtypes = [wintypes.WORD, ctypes.POINTER(WSADATA)]
-WSAStartup.restype = wintypes.INT
-
-WSACleanup = windll.Ws2_32.WSACleanup
-WSACleanup.argtypes = []
-WSACleanup.restype = wintypes.INT
-
-WSAAddressToStringW = windll.Ws2_32.WSAAddressToStringW
-WSAAddressToStringW.argtypes = [
- ctypes.POINTER(SOCKADDR), wintypes.DWORD, wintypes.LPVOID,
- wintypes.LPWSTR, ctypes.POINTER(wintypes.DWORD)]
-WSAAddressToStringW.restype = wintypes.INT
-
-Ws2_32 = windll.Ws2_32
-Ws2_32.inet_ntoa.restype = ctypes.c_char_p
-
-
-def init_wsa(version=VERSION_2_2):
- wsadata = WSADATA()
- WSAStartup(version, ctypes.byref(wsadata))
diff --git a/cloudinit/plugin_finder.py b/cloudinit/plugin_finder.py
deleted file mode 100644
index 862da66a..00000000
--- a/cloudinit/plugin_finder.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-"""Various base classes and implementations for finding *plugins*."""
-
-import abc
-import pkgutil
-
-import six
-
-from cloudinit import logging
-
-
-LOG = logging.getLogger(__name__)
-
-
-@six.add_metaclass(abc.ABCMeta)
-class BaseModuleIterator(object):
- """Base class for describing a *module iterator*
-
- A module iterator is a class that's capable of listing
- modules or packages from a specific location, which are
- already loaded.
- """
-
- def __init__(self, search_paths):
- self._search_paths = search_paths
-
- @abc.abstractmethod
- def list_modules(self):
- """List all the modules that this finder knows about."""
-
-
-class PkgutilModuleIterator(BaseModuleIterator):
- """A class based on the *pkgutil* module for discovering modules."""
-
- @staticmethod
- def _find_module(finder, module):
- """Delegate to the *finder* for finding the given module."""
- return finder.find_module(module).load_module(module)
-
- def list_modules(self):
- """List all modules that this class knows about."""
- for finder, name, _ in pkgutil.walk_packages(self._search_paths):
- try:
- module = self._find_module(finder, name)
- except ImportError:
- LOG.debug('Could not import the module %r using the '
- 'search path %r', name, finder.path)
- continue
-
- yield module
diff --git a/cloudinit/registry.py b/cloudinit/registry.py
deleted file mode 100644
index 04368ddf..00000000
--- a/cloudinit/registry.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-import copy
-
-
-class DictRegistry(object):
- """A simple registry for a mapping of objects."""
-
- def __init__(self):
- self.reset()
-
- def reset(self):
- self._items = {}
-
- def register_item(self, key, item):
- """Add item to the registry."""
- if key in self._items:
- raise ValueError(
- 'Item already registered with key {0}'.format(key))
- self._items[key] = item
-
- def unregister_item(self, key, force=True):
- """Remove item from the registry."""
- if key in self._items:
- del self._items[key]
- elif not force:
- raise KeyError("%s: key not present to unregister" % key)
-
- @property
- def registered_items(self):
- """All the items that have been registered.
-
- This cannot be used to modify the contents of the registry.
- """
- return copy.copy(self._items)
diff --git a/cloudinit/reporting/__init__.py b/cloudinit/reporting/__init__.py
deleted file mode 100644
index d0bc14e3..00000000
--- a/cloudinit/reporting/__init__.py
+++ /dev/null
@@ -1,238 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-"""
-cloud-init reporting framework
-
-The reporting framework is intended to allow all parts of cloud-init to
-report events in a structured manner.
-"""
-
-from cloudinit.registry import DictRegistry
-from cloudinit.reporting.handlers import available_handlers
-
-
-FINISH_EVENT_TYPE = 'finish'
-START_EVENT_TYPE = 'start'
-
-DEFAULT_CONFIG = {
- 'logging': {'type': 'log'},
-}
-
-
-class _nameset(set):
- def __getattr__(self, name):
- if name in self:
- return name
- raise AttributeError("%s not a valid value" % name)
-
-
-status = _nameset(("SUCCESS", "WARN", "FAIL"))
-
-
-class ReportingEvent(object):
- """Encapsulation of event formatting."""
-
- def __init__(self, event_type, name, description):
- self.event_type = event_type
- self.name = name
- self.description = description
-
- def as_string(self):
- """The event represented as a string."""
- return '{0}: {1}: {2}'.format(
- self.event_type, self.name, self.description)
-
- def as_dict(self):
- """The event represented as a dictionary."""
- return {'name': self.name, 'description': self.description,
- 'event_type': self.event_type}
-
-
-class FinishReportingEvent(ReportingEvent):
-
- def __init__(self, name, description, result=status.SUCCESS):
- super(FinishReportingEvent, self).__init__(
- FINISH_EVENT_TYPE, name, description)
- self.result = result
- if result not in status:
- raise ValueError("Invalid result: %s" % result)
-
- def as_string(self):
- return '{0}: {1}: {2}: {3}'.format(
- self.event_type, self.name, self.result, self.description)
-
- def as_dict(self):
- """The event represented as json friendly."""
- data = super(FinishReportingEvent, self).as_dict()
- data['result'] = self.result
- return data
-
-
-def update_configuration(config):
- """Update the instanciated_handler_registry.
-
- :param config:
- The dictionary containing changes to apply. If a key is given
- with a False-ish value, the registered handler matching that name
- will be unregistered.
- """
- for handler_name, handler_config in config.items():
- if not handler_config:
- instantiated_handler_registry.unregister_item(
- handler_name, force=True)
- continue
- handler_config = handler_config.copy()
- cls = available_handlers.registered_items[handler_config.pop('type')]
- instance = cls(**handler_config)
- instantiated_handler_registry.register_item(handler_name, instance)
-
-
-def report_event(event):
- """Report an event to all registered event handlers.
-
- This should generally be called via one of the other functions in
- the reporting module.
-
- :param event_type:
- The type of the event; this should be a constant from the
- reporting module.
- """
- for _, handler in instantiated_handler_registry.registered_items.items():
- handler.publish_event(event)
-
-
-def report_finish_event(event_name, event_description,
- result=status.SUCCESS):
- """Report a "finish" event.
-
- See :py:func:`.report_event` for parameter details.
- """
- event = FinishReportingEvent(event_name, event_description, result)
- return report_event(event)
-
-
-def report_start_event(event_name, event_description):
- """Report a "start" event.
-
- :param event_name:
- The name of the event; this should be a topic which events would
- share (e.g. it will be the same for start and finish events).
-
- :param event_description:
- A human-readable description of the event that has occurred.
- """
- event = ReportingEvent(START_EVENT_TYPE, event_name, event_description)
- return report_event(event)
-
-
-class ReportEventStack(object):
- """Context Manager for using :py:func:`report_event`
-
- This enables calling :py:func:`report_start_event` and
- :py:func:`report_finish_event` through a context manager.
-
- :param name:
- the name of the event
-
- :param description:
- the event's description, passed on to :py:func:`report_start_event`
-
- :param message:
- the description to use for the finish event. defaults to
- :param:description.
-
- :param parent:
- :type parent: :py:class:ReportEventStack or None
- The parent of this event. The parent is populated with
- results of all its children. The name used in reporting
- is /
-
- :param reporting_enabled:
- Indicates if reporting events should be generated.
- If not provided, defaults to the parent's value, or True if no parent
- is provided.
-
- :param result_on_exception:
- The result value to set if an exception is caught. default
- value is FAIL.
- """
- def __init__(self, name, description, message=None, parent=None,
- reporting_enabled=None, result_on_exception=status.FAIL):
- self.parent = parent
- self.name = name
- self.description = description
- self.message = message
- self.result_on_exception = result_on_exception
- self.result = status.SUCCESS
-
- # use parents reporting value if not provided
- if reporting_enabled is None:
- if parent:
- reporting_enabled = parent.reporting_enabled
- else:
- reporting_enabled = True
- self.reporting_enabled = reporting_enabled
-
- if parent:
- self.fullname = '/'.join((parent.fullname, name,))
- else:
- self.fullname = self.name
- self.children = {}
-
- def __repr__(self):
- return ("ReportEventStack(%s, %s, reporting_enabled=%s)" %
- (self.name, self.description, self.reporting_enabled))
-
- def __enter__(self):
- self.result = status.SUCCESS
- if self.reporting_enabled:
- report_start_event(self.fullname, self.description)
- if self.parent:
- self.parent.children[self.name] = (None, None)
- return self
-
- def _childrens_finish_info(self):
- for cand_result in (status.FAIL, status.WARN):
- for name, (value, msg) in self.children.items():
- if value == cand_result:
- return (value, self.message)
- return (self.result, self.message)
-
- @property
- def result(self):
- return self._result
-
- @result.setter
- def result(self, value):
- if value not in status:
- raise ValueError("'%s' not a valid result" % value)
- self._result = value
-
- @property
- def message(self):
- if self._message is not None:
- return self._message
- return self.description
-
- @message.setter
- def message(self, value):
- self._message = value
-
- def _finish_info(self, exc):
- # return tuple of description, and value
- if exc:
- return (self.result_on_exception, self.message)
- return self._childrens_finish_info()
-
- def __exit__(self, exc_type, exc_value, traceback):
- (result, msg) = self._finish_info(exc_value)
- if self.parent:
- self.parent.children[self.name] = (result, msg)
- if self.reporting_enabled:
- report_finish_event(self.fullname, msg, result)
-
-
-instantiated_handler_registry = DictRegistry()
-update_configuration(DEFAULT_CONFIG)
diff --git a/cloudinit/reporting/handlers.py b/cloudinit/reporting/handlers.py
deleted file mode 100644
index 24734b4e..00000000
--- a/cloudinit/reporting/handlers.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import abc
-import logging
-
-import six
-
-from cloudinit.registry import DictRegistry
-
-
-@six.add_metaclass(abc.ABCMeta)
-class ReportingHandler(object):
- """Base class for report handlers.
-
- Implement :meth:`~publish_event` for controlling what
- the handler does with an event.
- """
-
- @abc.abstractmethod
- def publish_event(self, event):
- """Publish an event to the ``INFO`` log level."""
-
-
-class LogHandler(ReportingHandler):
- """Publishes events to the cloud-init log at the ``INFO`` log level."""
-
- def publish_event(self, event):
- """Publish an event to the ``INFO`` log level."""
- logger = logging.getLogger(
- '.'.join(['cloudinit', 'reporting', event.event_type, event.name]))
- logger.info(event.as_string())
-
-
-available_handlers = DictRegistry()
-available_handlers.register_item('log', LogHandler)
diff --git a/cloudinit/safeyaml.py b/cloudinit/safeyaml.py
deleted file mode 100644
index a8f9d1ba..00000000
--- a/cloudinit/safeyaml.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import yaml as _yaml
-
-from cloudinit import util
-
-
-YAMLError = _yaml.YAMLError
-
-
-def load(path):
- """Load yaml string from a path and return the data represented.
-
- Exception will be raised if types other than the following are found:
- dict, int, float, string, list, unicode
- """
- return loads(util.load_file(path))
-
-
-def loads(blob):
- """Load yaml string and return the data represented.
-
- Exception will be raised if types other than the following are found:
- dict, int, float, string, list, unicode
- """
- return _yaml.safe_load(blob)
-
-
-def dumps(obj):
- """Dumps an object back into a yaml string."""
- formatted = _yaml.safe_dump(obj,
- line_break="\n",
- indent=4,
- explicit_start=True,
- explicit_end=True,
- default_flow_style=False)
- return formatted
diff --git a/cloudinit/shell.py b/cloudinit/shell.py
deleted file mode 100644
index c19e27f9..00000000
--- a/cloudinit/shell.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import argparse
-import sys
-
-from cloudinit import logging
-from cloudinit.version import version_string
-
-
-def populate_parser(parser, common, subcommands):
- """Populate an ArgumentParser with data rather than code
-
- This replaces boilerplate code with boilerplate data when populating a
- :py:class:`argparse.ArgumentParser`
-
- :param parser:
- the :py:mod:`argparse.ArgumentParser` to populate.
-
- :param common:
- a :py:func:`list` of tuples. Each tuple is args and kwargs that are
- passed onto :py:func:`argparse.ArgumentParser.add_argument`
-
- :param subcommands:
- a :py:func:dict of subcommands to add.
- The key is added as the subcommand name.
- 'func' is called to implement the subcommand.
- 'help' is set up as the subcommands help message
- entries in 'opts' are passed onto
- :py:func:`argparse.ArgumentParser.add_argument`
- """
- for (args, kwargs) in common:
- parser.add_argument(*args, **kwargs)
-
- subparsers = parser.add_subparsers()
- for subcmd in sorted(subcommands):
- val = subcommands[subcmd]
- sparser = subparsers.add_parser(subcmd, help=val['help'])
- sparser.set_defaults(func=val['func'], name=subcmd)
- for (args, kwargs) in val.get('opts', {}):
- sparser.add_argument(*args, **kwargs)
-
-
-def main(args=sys.argv):
- parser = argparse.ArgumentParser(prog='cloud-init')
-
- populate_parser(parser, COMMON_ARGS, SUBCOMMANDS)
- parsed = parser.parse_args(args[1:])
-
- if not hasattr(parsed, 'func'):
- parser.error('too few arguments')
- logging.configure_logging(log_to_console=parsed.log_to_console)
- parsed.func(parsed)
- return 0
-
-
-def main_version(args):
- sys.stdout.write("cloud-init {0}\n".format(version_string()))
-
-
-def unimplemented_subcommand(args):
- raise NotImplementedError(
- "sub command '{0}' is not implemented".format(args.name))
-
-
-COMMON_ARGS = [
- (('--log-to-console',), {'action': 'store_true', 'default': False}),
- (('--verbose', '-v'), {'action': 'count', 'default': 0}),
-]
-
-SUBCOMMANDS = {
- # The stages a normal boot takes
- 'network': {
- 'func': unimplemented_subcommand,
- 'help': 'locate and apply networking configuration',
- },
- 'search': {
- 'func': unimplemented_subcommand,
- 'help': 'search available data sources',
- },
- 'config': {
- 'func': unimplemented_subcommand,
- 'help': 'run available config modules',
- },
- 'config-final': {
- 'func': unimplemented_subcommand,
- 'help': 'run "final" config modules',
- },
- # utility
- 'version': {
- 'func': main_version,
- 'help': 'print cloud-init version',
- },
- 'all': {
- 'func': unimplemented_subcommand,
- 'help': 'run all stages as if from boot',
- 'opts': [
- (('--clean',),
- {'help': 'clear any prior system state',
- 'action': 'store_true', 'default': False})],
- },
- 'clean': {
- 'func': unimplemented_subcommand,
- 'help': 'clear any prior system state.',
- 'opts': [
- (('-F', '--full'),
- {'help': 'be more complete (remove logs).',
- 'default': False, 'action': 'store_true'}),
- ],
- },
- 'query': {
- 'func': unimplemented_subcommand,
- 'help': 'query system state',
- 'opts': [
- (('--json',),
- {'help': 'output in json format',
- 'action': 'store_true', 'default': False})]
- },
-}
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py
deleted file mode 100644
index 20b32a23..00000000
--- a/cloudinit/sources/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
diff --git a/cloudinit/sources/base.py b/cloudinit/sources/base.py
deleted file mode 100644
index 65f58538..00000000
--- a/cloudinit/sources/base.py
+++ /dev/null
@@ -1,217 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import abc
-import itertools
-
-import six
-
-from cloudinit import exceptions
-from cloudinit import logging
-from cloudinit import sources
-from cloudinit.sources import strategy
-
-
-LOG = logging.getLogger(__name__)
-
-
-class APIResponse(object):
- """Holds API response content
-
- To access the content in the binary format, use the
- `buffer` attribute, while the unicode content can be
- accessed by calling `str` over this (or by accessing
- the `decoded_buffer` property).
- """
-
- def __init__(self, buffer, encoding="utf-8"):
- self.buffer = buffer
- self.encoding = encoding
- self._decoded_buffer = None
-
- @property
- def decoded_buffer(self):
- # Avoid computing this again and again (although multiple threads
- # may decode it if they all get in here at the same time, but meh
- # thats ok).
- if self._decoded_buffer is None:
- self._decoded_buffer = self.buffer.decode(self.encoding)
- return self._decoded_buffer
-
- def __str__(self):
- return self.decoded_buffer
-
-
-class DataSourceLoader(object):
- """Class for retrieving an available data source instance
-
- :param names:
- A list of possible data source names, from which the loader
- should pick. This can be used to filter the data sources
- that can be found from outside of cloudinit control.
-
- :param module_iterator:
- An instance of :class:`cloudinit.plugin_finder.BaseModuleIterator`,
- which is used to find possible modules where the data sources
- can be found.
-
- :param strategies:
- An iterator of search strategy classes, where each strategy is capable
- of filtering the data sources that can be used by cloudinit.
- Possible strategies includes serial data source search or
- parallel data source or filtering data sources according to
- some criteria (only network data sources)
-
- """
-
- def __init__(self, names, module_iterator, strategies):
- self._names = names
- self._module_iterator = module_iterator
- self._strategies = strategies
-
- @staticmethod
- def _implements_source_api(module):
- """Check if the given module implements the data source API."""
- return hasattr(module, 'data_sources')
-
- def _valid_modules(self):
- """Return all the modules that are *valid*
-
- Valid modules are those that implements a particular API
- for declaring the data sources it exports.
- """
- modules = self._module_iterator.list_modules()
- return filter(self._implements_source_api, modules)
-
- def all_data_sources(self):
- """Get all the data source classes that this finder knows about."""
- return itertools.chain.from_iterable(
- module.data_sources()
- for module in self._valid_modules())
-
- def valid_data_sources(self):
- """Get the data sources that are valid for this run."""
- data_sources = self.all_data_sources()
- # Instantiate them before passing to the strategies.
- data_sources = (data_source() for data_source in data_sources)
-
- for strategy_instance in self._strategies:
- data_sources = strategy_instance.search_data_sources(data_sources)
- return data_sources
-
-
-@six.add_metaclass(abc.ABCMeta)
-class BaseDataSource(object):
- """Base class for the data sources."""
-
- datasource_config = {}
-
- def __init__(self, config=None):
- self._cache = {}
- # TODO(cpopa): merge them instead.
- self._config = config or self.datasource_config
-
- def _get_cache_data(self, path):
- """Do a metadata lookup for the given *path*
-
- This will return the available metadata under *path*,
- while caching the result, so that a next call will not do
- an additional API call.
- """
- if path not in self._cache:
- self._cache[path] = self._get_data(path)
-
- return self._cache[path]
-
- @abc.abstractmethod
- def load(self):
- """Try to load this metadata service.
-
- This should return ``True`` if the service was loaded properly,
- ``False`` otherwise.
- """
-
- @abc.abstractmethod
- def _get_data(self, path):
- """Retrieve the metadata exported under the `path` key.
-
- This should return an instance of :class:`APIResponse`.
- """
-
- @abc.abstractmethod
- def version(self):
- """Get the version of the current data source."""
-
- def instance_id(self):
- """Get this instance's id."""
-
- def user_data(self):
- """Get the user data available for this instance."""
-
- def vendor_data(self):
- """Get the vendor data available for this instance."""
-
- def host_name(self):
- """Get the hostname available for this instance."""
-
- def public_keys(self):
- """Get the public keys available for this instance."""
-
- def network_config(self):
- """Get the specified network config, if any."""
-
- def admin_password(self):
- """Get the admin password."""
-
- def post_password(self, password):
- """Post the password to the metadata service."""
-
- def can_update_password(self):
- """Check if this data source can update the admin password."""
-
- def is_password_changed(self):
- """Check if the data source has a new password for this instance."""
- return False
-
- def is_password_set(self):
- """Check if the password was already posted to the metadata service."""
-
-
-def get_data_source(names, module_iterator, strategies=None):
- """Get an instance of any data source available.
-
- :param names:
- A list of possible data source names, from which the loader
- should pick. This can be used to filter the data sources
- that can be found from outside of cloudinit control.
-
- :param module_iterator:
- A subclass of :class:`cloudinit.plugin_finder.BaseModuleIterator`,
- which is used to find possible modules where the data sources
- can be found.
-
- :param strategies:
- An iterator of search strategy classes, where each strategy is capable
- of filtering the data sources that can be used by cloudinit.
- """
- if names:
- default_strategies = [strategy.FilterNameStrategy(names)]
- else:
- default_strategies = []
- if strategies is None:
- strategies = []
-
- strategy_instances = [strategy_cls() for strategy_cls in strategies]
- strategies = default_strategies + strategy_instances
-
- iterator = module_iterator(sources.__path__)
- loader = DataSourceLoader(names, iterator, strategies)
- valid_sources = loader.valid_data_sources()
-
- data_source = next(valid_sources, None)
- if not data_source:
- raise exceptions.CloudInitError('No available data source found')
-
- return data_source
diff --git a/cloudinit/sources/openstack/__init__.py b/cloudinit/sources/openstack/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/cloudinit/sources/openstack/base.py b/cloudinit/sources/openstack/base.py
deleted file mode 100644
index 01f59a38..00000000
--- a/cloudinit/sources/openstack/base.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-"""Base classes for interacting with OpenStack data sources."""
-
-import abc
-import json
-import logging
-import os
-
-import six
-
-from cloudinit.sources import base
-
-__all__ = ('BaseOpenStackSource', )
-
-_PAYLOAD_KEY = "content_path"
-_ADMIN_PASSWORD = "admin_pass"
-LOG = logging.getLogger(__name__)
-_OS_LATEST = 'latest'
-_OS_FOLSOM = '2012-08-10'
-_OS_GRIZZLY = '2013-04-04'
-_OS_HAVANA = '2013-10-17'
-# Keep this in chronological order. New supported versions go at the end.
-_OS_VERSIONS = (
- _OS_FOLSOM,
- _OS_GRIZZLY,
- _OS_HAVANA,
-)
-
-
-@six.add_metaclass(abc.ABCMeta)
-class BaseOpenStackSource(base.BaseDataSource):
- """Base classes for interacting with an OpenStack data source.
-
- This is useful for both the HTTP data source, as well for
- ConfigDrive.
- """
- def __init__(self):
- super(BaseOpenStackSource, self).__init__()
- self._version = None
-
- @abc.abstractmethod
- def _available_versions(self):
- """Get the available metadata versions."""
-
- @abc.abstractmethod
- def _path_join(self, path, *addons):
- """Join one or more components together."""
-
- def version(self):
- """Get the underlying data source version."""
- return self._version
-
- def _working_version(self):
- versions = self._available_versions()
- # OS_VERSIONS is stored in chronological order, so
- # reverse it to check newest first.
- supported = reversed(_OS_VERSIONS)
- selected_version = next((version for version in supported
- if version in versions), _OS_LATEST)
-
- LOG.debug("Selected version %r from %s", selected_version, versions)
- return selected_version
-
- def _get_content(self, name):
- path = self._path_join('openstack', 'content', name)
- return self._get_cache_data(path)
-
- def _get_meta_data(self):
- path = self._path_join('openstack', self._version, 'meta_data.json')
- data = self._get_cache_data(path)
- if data:
- return json.loads(str(data))
-
- def load(self):
- self._version = self._working_version()
- super(BaseOpenStackSource, self).load()
-
- def user_data(self):
- path = self._path_join('openstack', self._version, 'user_data')
- return self._get_cache_data(path).buffer
-
- def vendor_data(self):
- path = self._path_join('openstack', self._version, 'vendor_data.json')
- return self._get_cache_data(path).buffer
-
- def instance_id(self):
- return self._get_meta_data().get('uuid')
-
- def host_name(self):
- return self._get_meta_data().get('hostname')
-
- def public_keys(self):
- public_keys = self._get_meta_data().get('public_keys')
- if public_keys:
- return list(public_keys.values())
- return []
-
- def network_config(self):
- network_config = self._get_meta_data().get('network_config')
- if not network_config:
- return None
- if _PAYLOAD_KEY not in network_config:
- return None
-
- content_path = network_config[_PAYLOAD_KEY]
- content_name = os.path.basename(content_path)
- return str(self._get_content(content_name))
-
- def admin_password(self):
- meta_data = self._get_meta_data()
- meta = meta_data.get('meta', {})
- return meta.get(_ADMIN_PASSWORD) or meta_data.get(_ADMIN_PASSWORD)
diff --git a/cloudinit/sources/openstack/httpopenstack.py b/cloudinit/sources/openstack/httpopenstack.py
deleted file mode 100644
index 618a62df..00000000
--- a/cloudinit/sources/openstack/httpopenstack.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import logging
-import os
-import posixpath
-import re
-
-from cloudinit import exceptions
-from cloudinit.osys import base
-from cloudinit.sources import base as base_source
-from cloudinit.sources.openstack import base as baseopenstack
-from cloudinit import url_helper
-
-
-LOG = logging.getLogger(__name__)
-IS_WINDOWS = os.name == 'nt'
-# Not necessarily the same as using datetime.strftime,
-# but should be enough for our use case.
-VERSION_REGEX = re.compile('^\d{4}-\d{2}-\d{2}$')
-
-
-class HttpOpenStackSource(baseopenstack.BaseOpenStackSource):
- """Class for exporting the HTTP OpenStack data source."""
-
- datasource_config = {
- 'max_wait': 120,
- 'timeout': 10,
- 'metadata_url': 'http://169.254.169.254/',
- 'post_password_version': '2013-04-04',
- 'retries': 3,
- }
-
- @staticmethod
- def _enable_metadata_access(metadata_url):
- if IS_WINDOWS:
- osutils = base.get_osutils()
- osutils.network.set_metadata_ip_route(metadata_url)
-
- @staticmethod
- def _path_join(path, *addons):
- return posixpath.join(path, *addons)
-
- @staticmethod
- def _valid_api_version(version):
- if version == 'latest':
- return version
- return VERSION_REGEX.match(version)
-
- def _available_versions(self):
- content = str(self._get_cache_data("openstack"))
- versions = list(filter(None, content.splitlines()))
- if not versions:
- msg = 'No metadata versions were found.'
- raise exceptions.CloudInitError(msg)
-
- for version in versions:
- if not self._valid_api_version(version):
- msg = 'Invalid API version %r' % (version,)
- raise exceptions.CloudInitError(msg)
-
- return versions
-
- def _get_data(self, path):
- norm_path = self._path_join(self._config['metadata_url'], path)
- LOG.debug('Getting metadata from: %s', norm_path)
- response = url_helper.wait_any_url([norm_path],
- timeout=self._config['timeout'],
- max_wait=self._config['max_wait'])
- if response:
- _, request = response
- return base_source.APIResponse(request.contents,
- encoding=request.encoding)
-
- msg = "Metadata for url {0} was not accessible in due time"
- raise exceptions.CloudInitError(msg.format(norm_path))
-
- def _post_data(self, path, data):
- norm_path = self._path_join(self._config['metadata_url'], path)
- LOG.debug('Posting metadata to: %s', norm_path)
- url_helper.read_url(norm_path, data=data,
- retries=self._config['retries'],
- timeout=self._config['timeout'])
-
- @property
- def _password_path(self):
- return 'openstack/%s/password' % self._version
-
- def load(self):
- metadata_url = self._config['metadata_url']
- self._enable_metadata_access(metadata_url)
- super(HttpOpenStackSource, self).load()
-
- try:
- self._get_meta_data()
- return True
- except Exception:
- LOG.warning('Metadata not found at URL %r', metadata_url)
- return False
-
- def can_update_password(self):
- """Check if the password can be posted for the current data source."""
- password = map(int, self._config['post_password_version'].split("-"))
- if self._version == 'latest':
- current = (0, )
- else:
- current = map(int, self._version.split("-"))
- return tuple(current) >= tuple(password)
-
- @property
- def is_password_set(self):
- path = self._password_path
- content = self._get_cache_data(path).buffer
- return len(content) > 0
-
- def post_password(self, password):
- try:
- self._post_data(self._password_path, password)
- return True
- except url_helper.UrlError as ex:
- if ex.status_code == url_helper.CONFLICT:
- # Password already set
- return False
- else:
- raise
-
-
-def data_sources():
- """Get the data sources exported in this module."""
- return (HttpOpenStackSource,)
diff --git a/cloudinit/sources/strategy.py b/cloudinit/sources/strategy.py
deleted file mode 100644
index 547f8b61..00000000
--- a/cloudinit/sources/strategy.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import abc
-
-import six
-
-from cloudinit import logging
-
-
-LOG = logging.getLogger(__name__)
-
-
-@six.add_metaclass(abc.ABCMeta)
-class BaseSearchStrategy(object):
- """Declare search strategies for data sources
-
- A *search strategy* represents a decoupled way of choosing
- one or more data sources from a list of data sources.
- Each strategy can be used interchangeably and they can
- be composed. For instance, once can apply a filtering strategy
- over a parallel search strategy, which looks for the available
- data sources.
- """
-
- @abc.abstractmethod
- def search_data_sources(self, data_sources):
- """Search the possible data sources for this strategy
-
- The method should filter the data sources that can be
- considered *valid* for the given strategy.
-
- :param data_sources:
- An iterator of data source instances, where the lookup
- will be done.
- """
-
- @staticmethod
- def is_datasource_available(data_source):
- """Check if the given *data_source* is considered *available*
-
- A data source is considered available if it can be loaded,
- but other strategies could implement their own behaviour.
- """
- try:
- if data_source.load():
- return True
- except Exception:
- LOG.error("Failed to load data source %r", data_source)
- return False
-
-
-class FilterNameStrategy(BaseSearchStrategy):
- """A strategy for filtering data sources by name
-
- :param names:
- A list of strings, where each string is a name for a possible
- data source. Only the data sources that are in this list will
- be loaded and filtered.
- """
-
- def __init__(self, names=None):
- self._names = names
- super(FilterNameStrategy, self).__init__()
-
- def search_data_sources(self, data_sources):
- return (source for source in data_sources
- if source.__class__.__name__ in self._names)
-
-
-class SerialSearchStrategy(BaseSearchStrategy):
- """A strategy that chooses a data source in serial."""
-
- def search_data_sources(self, data_sources):
- for data_source in data_sources:
- if self.is_datasource_available(data_source):
- yield data_source
-
-
-class FilterVersionStrategy(BaseSearchStrategy):
- """A strategy for filtering data sources by their version
-
- :param versions:
- A list of strings, where each strings is a possible
- version that a data source can have.
- """
-
- def __init__(self, versions=None):
- if versions is None:
- versions = []
- self._versions = versions
- super(FilterVersionStrategy, self).__init__()
-
- def search_data_sources(self, data_sources):
- return (source for source in data_sources
- if source.version() in self._versions)
diff --git a/cloudinit/templater.py b/cloudinit/templater.py
deleted file mode 100644
index b9bfe87b..00000000
--- a/cloudinit/templater.py
+++ /dev/null
@@ -1,107 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import collections
-import os
-import re
-
-try:
- import jinja2
- from jinja2 import Template as JTemplate
- JINJA_AVAILABLE = True
-except (ImportError, AttributeError):
- JINJA_AVAILABLE = False # noqa
-
-from cloudinit import logging
-
-
-LOG = logging.getLogger(__name__)
-TYPE_MATCHER = re.compile(r"##\s*template:(.*)", re.I)
-BASIC_MATCHER = re.compile(r'\$\{([A-Za-z0-9_.]+)\}|\$([A-Za-z0-9_.]+)')
-
-
-def basic_render(content, params):
- """This does simple replacement of bash variable like templates.
-
- It identifies patterns like ${a} or $a and can also identify patterns like
- ${a.b} or $a.b which will look for a key 'b' in the dictionary rooted
- by key 'a'.
- """
-
- def replacer(match):
- # Only 1 of the 2 groups will actually have a valid entry.
- name = match.group(1) or match.group(2)
- if name is None:
- # not sure how this can possibly occur
- raise RuntimeError("Match encountered but no valid group present")
- path = collections.deque(name.split("."))
- selected_params = params
- while len(path) > 1:
- key = path.popleft()
- if not isinstance(selected_params, dict):
- raise TypeError(
- "Can not traverse into non-dictionary '%s' of type %s "
- "while looking for subkey '%s'" %
- (selected_params, type(selected_params), key))
- selected_params = selected_params[key]
- key = path.popleft()
- if not isinstance(selected_params, dict):
- raise TypeError("Can not extract key '%s' from non-dictionary"
- " '%s' of type %s"
- % (key, selected_params, type(selected_params)))
- return str(selected_params[key])
-
- return BASIC_MATCHER.sub(replacer, content)
-
-
-def detect_template(text):
-
- def jinja_render(content, params):
- # keep_trailing_newline is in jinja2 2.7+, not 2.6
- add = "\n" if content.endswith("\n") else ""
- return JTemplate(content,
- undefined=jinja2.StrictUndefined,
- trim_blocks=True).render(**params) + add
-
- if "\n" in text:
- ident, rest = text.split("\n", 1)
- else:
- ident = text
- rest = ''
- type_match = TYPE_MATCHER.match(ident)
- if not type_match:
- return ('basic', basic_render, text)
- else:
- template_type = type_match.group(1).lower().strip()
- if template_type not in ('jinja', 'basic'):
- raise ValueError("Unknown template rendering type '%s' requested"
- % template_type)
- if template_type == 'jinja' and not JINJA_AVAILABLE:
- raise ValueError("Template requested jinja as renderer, but Jinja "
- "is not available.")
- elif template_type == 'jinja' and JINJA_AVAILABLE:
- return ('jinja', jinja_render, rest)
- # Only thing left over is the basic renderer (it is always available).
- return ('basic', basic_render, rest)
-
-
-def render_from_file(fn, params, encoding='utf-8'):
- with open(fn, 'rb') as fh:
- content = fh.read()
- content = content.decode(encoding)
- _, renderer, content = detect_template(content)
- return renderer(content, params)
-
-
-def render_to_file(fn, outfn, params, mode=0o644, encoding='utf-8'):
- contents = render_from_file(fn, params, encoding=encoding)
- with open(outfn, 'wb') as fh:
- fh.write(contents.encode(encoding))
- os.chmod(outfn, mode)
-
-
-def render_string(content, params):
- _, renderer, content = detect_template(content)
- return renderer(content, params)
diff --git a/cloudinit/tests/__init__.py b/cloudinit/tests/__init__.py
deleted file mode 100644
index 719c7b62..00000000
--- a/cloudinit/tests/__init__.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import httpretty
-import testtools
-
-
-class TestCase(testtools.TestCase):
- """Base class for all cloud-init test cases."""
-
- def setUp(self):
- super(TestCase, self).setUp()
- # Do not allow any unknown network connections to get triggered...
- httpretty.HTTPretty.allow_net_connect = False
-
- def tearDown(self):
- super(TestCase, self).tearDown()
- # Ok allow it again....
- httpretty.HTTPretty.allow_net_connect = True
diff --git a/cloudinit/tests/osys/__init__.py b/cloudinit/tests/osys/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/cloudinit/tests/osys/test_base.py b/cloudinit/tests/osys/test_base.py
deleted file mode 100644
index 7129571f..00000000
--- a/cloudinit/tests/osys/test_base.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2015 Canonical Ltd.
-# Copyright 2015 Cloudbase Solutions Srl
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from cloudinit.osys import base
-from cloudinit.tests import TestCase
-from cloudinit.tests.util import mock
-
-
-class TestOSUtils(TestCase):
-
- @mock.patch('importlib.import_module')
- @mock.patch('platform.linux_distribution')
- @mock.patch('platform.system')
- def _test_getosutils(self, mock_system,
- mock_linux_distribution, mock_import_module,
- linux=False):
- if linux:
- os_name = 'Linux'
- mock_linux_distribution.return_value = (os_name, None, None)
- else:
- os_name = 'Windows'
- mock_system.return_value = os_name
- mock_linux_distribution.return_value = (None, None, None)
-
- module = base.get_osutils()
-
- mock_import_module.assert_called_once_with(
- "cloudinit.osys.{0}.base".format(os_name.lower()))
- self.assertEqual(mock_import_module.return_value.OSUtils,
- module)
- if linux:
- mock_linux_distribution.assert_called_once_with()
- self.assertFalse(mock_system.called)
- else:
- mock_linux_distribution.assert_called_once_with()
- mock_system.assert_called_once_with()
-
- def test_getosutils(self):
- self._test_getosutils(linux=True)
- self._test_getosutils(linux=False)
diff --git a/cloudinit/tests/osys/windows/__init__.py b/cloudinit/tests/osys/windows/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/cloudinit/tests/osys/windows/test_general.py b/cloudinit/tests/osys/windows/test_general.py
deleted file mode 100644
index 1b2e4556..00000000
--- a/cloudinit/tests/osys/windows/test_general.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import importlib
-
-from cloudinit import exceptions
-from cloudinit.tests import TestCase
-from cloudinit.tests.util import mock
-
-
-class TestWindowsGeneral(TestCase):
-
- def setUp(self):
- super(TestWindowsGeneral, self).setUp()
- self._ctypes_mock = mock.Mock()
- self._util_mock = mock.MagicMock()
- self._module_patcher = mock.patch.dict(
- 'sys.modules',
- {'ctypes': self._ctypes_mock,
- 'cloudinit.osys.windows.util': self._util_mock})
-
- self._module_patcher.start()
- self._general_module = importlib.import_module(
- "cloudinit.osys.windows.general")
- self._kernel32 = self._general_module.kernel32
- self._general = self._general_module.General()
-
- def tearDown(self):
- super(TestWindowsGeneral, self).tearDown()
- self._module_patcher.stop()
-
- def _test_check_os_version(self, ret_value, error_value=None):
- verset_return = 2
- self._kernel32.VerSetConditionMask.return_value = (
- verset_return)
- self._kernel32.VerifyVersionInfoW.return_value = ret_value
- self._kernel32.GetLastError.return_value = error_value
- old_version = self._kernel32.ERROR_OLD_WIN_VERSION
-
- if error_value and error_value is not old_version:
- self.assertRaises(exceptions.CloudInitError,
- self._general.check_os_version, 3, 1, 2)
- self._kernel32.GetLastError.assert_called_once_with()
-
- else:
- response = self._general.check_os_version(3, 1, 2)
- self._ctypes_mock.sizeof.assert_called_once_with(
- self._kernel32.Win32_OSVERSIONINFOEX_W)
- self.assertEqual(
- 3, self._kernel32.VerSetConditionMask.call_count)
-
- mask = (self._kernel32.VER_MAJORVERSION |
- self._kernel32.VER_MINORVERSION |
- self._kernel32.VER_BUILDNUMBER)
- self._kernel32.VerifyVersionInfoW.assert_called_with(
- self._ctypes_mock.byref.return_value, mask, verset_return)
-
- if error_value is old_version:
- self._kernel32.GetLastError.assert_called_with()
- self.assertFalse(response)
- else:
- self.assertTrue(response)
-
- def test_check_os_version(self):
- m = mock.MagicMock()
- self._test_check_os_version(ret_value=m)
-
- def test_check_os_version_expect_false(self):
- self._test_check_os_version(
- ret_value=None, error_value=self._kernel32.ERROR_OLD_WIN_VERSION)
diff --git a/cloudinit/tests/osys/windows/test_network.py b/cloudinit/tests/osys/windows/test_network.py
deleted file mode 100644
index 5fa2581b..00000000
--- a/cloudinit/tests/osys/windows/test_network.py
+++ /dev/null
@@ -1,361 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import importlib
-import subprocess
-
-from cloudinit import exceptions
-from cloudinit import tests
-from cloudinit.tests.util import LogSnatcher
-from cloudinit.tests.util import mock
-
-
-class TestNetworkWindows(tests.TestCase):
-
- def setUp(self):
- super(TestNetworkWindows, self).setUp()
-
- self._ctypes_mock = mock.MagicMock()
- self._winreg_mock = mock.Mock()
- self._win32com_mock = mock.Mock()
- self._wmi_mock = mock.Mock()
-
- self._module_patcher = mock.patch.dict(
- 'sys.modules',
- {'ctypes': self._ctypes_mock,
- 'win32com': self._win32com_mock,
- 'wmi': self._wmi_mock,
- 'six.moves.winreg': self._winreg_mock})
-
- self._module_patcher.start()
- self._iphlpapi = mock.Mock()
- self._kernel32 = mock.Mock()
- self._ws2_32 = mock.Mock()
-
- self._network_module = importlib.import_module(
- 'cloudinit.osys.windows.network')
- self._network_module.iphlpapi = self._iphlpapi
- self._network_module.kernel32 = self._kernel32
- self._network_module.ws2_32 = self._ws2_32
-
- self._network = self._network_module.Network()
-
- def tearDown(self):
- super(TestNetworkWindows, self).tearDown()
-
- self._module_patcher.stop()
-
- def _test__heap_alloc(self, fail):
- mock_heap = mock.Mock()
- mock_size = mock.Mock()
-
- if fail:
- self._kernel32.HeapAlloc.return_value = None
-
- e = self.assertRaises(exceptions.CloudInitError,
- self._network_module._heap_alloc,
- mock_heap, mock_size)
-
- self.assertEqual('Unable to allocate memory for the IP '
- 'forward table', str(e))
- else:
- result = self._network_module._heap_alloc(mock_heap, mock_size)
- self.assertEqual(self._kernel32.HeapAlloc.return_value, result)
-
- self._kernel32.HeapAlloc.assert_called_once_with(
- mock_heap, 0, self._ctypes_mock.c_size_t(mock_size.value))
-
- def test__heap_alloc_error(self):
- self._test__heap_alloc(fail=True)
-
- def test__heap_alloc_no_error(self):
- self._test__heap_alloc(fail=False)
-
- def _check_raises_forward(self):
- with self._network._get_forward_table():
- pass
-
- def test__get_forward_table_no_memory(self):
- self._network_module._heap_alloc = mock.Mock()
- error_msg = 'Unable to allocate memory for the IP forward table'
- exc = exceptions.CloudInitError(error_msg)
- self._network_module._heap_alloc.side_effect = exc
-
- e = self.assertRaises(exceptions.CloudInitError,
- self._check_raises_forward)
-
- self.assertEqual(error_msg, str(e))
- self._network_module._heap_alloc.assert_called_once_with(
- self._kernel32.GetProcessHeap.return_value,
- self._ctypes_mock.wintypes.ULONG.return_value)
-
- def test__get_forward_table_insufficient_buffer_no_memory(self):
- self._kernel32.HeapAlloc.side_effect = (mock.sentinel.table_mem, None)
- self._iphlpapi.GetIpForwardTable.return_value = (
- self._iphlpapi.ERROR_INSUFFICIENT_BUFFER)
-
- self.assertRaises(exceptions.CloudInitError,
- self._check_raises_forward)
-
- table = self._ctypes_mock.cast.return_value
- self._iphlpapi.GetIpForwardTable.assert_called_once_with(
- table,
- self._ctypes_mock.byref.return_value, 0)
- heap_calls = [
- mock.call(self._kernel32.GetProcessHeap.return_value, 0, table),
- mock.call(self._kernel32.GetProcessHeap.return_value, 0, table)
- ]
- self.assertEqual(heap_calls, self._kernel32.HeapFree.mock_calls)
-
- def _test__get_forward_table(self, reallocation=False,
- insufficient_buffer=False,
- fail=False):
- if fail:
- e = self.assertRaises(exceptions.CloudInitError,
- self._check_raises_forward)
- msg = ('Unable to get IP forward table. Error: %s'
- % mock.sentinel.error)
- self.assertEqual(msg, str(e))
- else:
- with self._network._get_forward_table() as table:
- pass
- pointer = self._ctypes_mock.POINTER(
- self._iphlpapi.Win32_MIB_IPFORWARDTABLE)
- expected_forward_table = self._ctypes_mock.cast(
- self._kernel32.HeapAlloc.return_value, pointer)
- self.assertEqual(expected_forward_table, table)
-
- heap_calls = [
- mock.call(self._kernel32.GetProcessHeap.return_value, 0,
- self._ctypes_mock.cast.return_value)
- ]
- forward_calls = [
- mock.call(self._ctypes_mock.cast.return_value,
- self._ctypes_mock.byref.return_value, 0),
- ]
- if insufficient_buffer:
- # We expect two calls for GetIpForwardTable
- forward_calls.append(forward_calls[0])
- if reallocation:
- heap_calls.append(heap_calls[0])
- self.assertEqual(heap_calls, self._kernel32.HeapFree.mock_calls)
- self.assertEqual(forward_calls,
- self._iphlpapi.GetIpForwardTable.mock_calls)
-
- def test__get_forward_table_sufficient_buffer(self):
- self._iphlpapi.GetIpForwardTable.return_value = None
- self._test__get_forward_table()
-
- def test__get_forward_table_insufficient_buffer_reallocate(self):
- self._kernel32.HeapAlloc.side_effect = (
- mock.sentinel.table_mem, mock.sentinel.table_mem)
- self._iphlpapi.GetIpForwardTable.side_effect = (
- self._iphlpapi.ERROR_INSUFFICIENT_BUFFER, None)
-
- self._test__get_forward_table(reallocation=True,
- insufficient_buffer=True)
-
- def test__get_forward_table_insufficient_buffer_other_error(self):
- self._kernel32.HeapAlloc.side_effect = (
- mock.sentinel.table_mem, mock.sentinel.table_mem)
- self._iphlpapi.GetIpForwardTable.side_effect = (
- self._iphlpapi.ERROR_INSUFFICIENT_BUFFER, mock.sentinel.error)
-
- self._test__get_forward_table(reallocation=True,
- insufficient_buffer=True,
- fail=True)
-
- @mock.patch('cloudinit.osys.windows.network.Network.routes')
- def test_default_gateway_no_gateway(self, mock_routes):
- mock_routes.return_value = iter((mock.Mock(), mock.Mock()))
-
- self.assertIsNone(self._network.default_gateway())
-
- mock_routes.assert_called_once_with()
-
- @mock.patch('cloudinit.osys.windows.network.Network.routes')
- def test_default_gateway(self, mock_routes):
- default_gateway = mock.Mock()
- default_gateway.destination = '0.0.0.0'
- mock_routes.return_value = iter((mock.Mock(), default_gateway))
-
- gateway = self._network.default_gateway()
-
- self.assertEqual(default_gateway, gateway)
-
- def test_route_is_static(self):
- bad_route = self._network_module.Route(
- destination=None, netmask=None,
- gateway=None, interface=None, metric=None,
- flags=404)
- good_route = self._network_module.Route(
- destination=None, netmask=None,
- gateway=None, interface=None, metric=None,
- flags=self._network_module.MIB_IPPROTO_NETMGMT)
-
- self.assertTrue(good_route.is_static)
- self.assertFalse(bad_route.is_static)
-
- @mock.patch('subprocess.Popen')
- def _test_route_add(self, mock_popen, err):
- mock_route = mock.Mock()
- mock_route.destination = mock.sentinel.destination
- mock_route.netmask = mock.sentinel.netmask
- mock_route.gateway = mock.sentinel.gateway
- args = ['ROUTE', 'ADD', mock.sentinel.destination,
- 'MASK', mock.sentinel.netmask,
- mock.sentinel.gateway]
- mock_popen.return_value.returncode = err
- mock_popen.return_value.communicate.return_value = (None, err)
-
- if err:
- e = self.assertRaises(exceptions.CloudInitError,
- self._network_module.Route.add,
- mock_route)
- msg = "Unable to add route: %s" % err
- self.assertEqual(msg, str(e))
-
- else:
- self._network_module.Route.add(mock_route)
- mock_popen.assert_called_once_with(args, shell=False,
- stderr=subprocess.PIPE)
-
- def test_route_add_fails(self):
- self._test_route_add(err=1)
-
- def test_route_add_works(self):
- self._test_route_add(err=0)
-
- @mock.patch('cloudinit.osys.windows.network.Network._get_forward_table')
- def test_routes(self, mock_forward_table):
- def _same(arg):
- return arg._mock_name.encode()
-
- route = mock.MagicMock()
- mock_cast_result = mock.Mock()
- mock_cast_result.contents = [route]
- self._ctypes_mock.cast.return_value = mock_cast_result
- self._network_module.ws2_32.Ws2_32.inet_ntoa.side_effect = _same
- route.dwForwardIfIndex = 'dwForwardIfIndex'
- route.dwForwardProto = 'dwForwardProto'
- route.dwForwardMetric1 = 'dwForwardMetric1'
- routes = self._network.routes()
-
- mock_forward_table.assert_called_once_with()
- enter = mock_forward_table.return_value.__enter__
- enter.assert_called_once_with()
- exit_ = mock_forward_table.return_value.__exit__
- exit_.assert_called_once_with(None, None, None)
- self.assertEqual(1, len(routes))
- given_route = routes[0]
- self.assertEqual('dwForwardDest', given_route.destination)
- self.assertEqual('dwForwardNextHop', given_route.gateway)
- self.assertEqual('dwForwardMask', given_route.netmask)
- self.assertEqual('dwForwardIfIndex', given_route.interface)
- self.assertEqual('dwForwardMetric1', given_route.metric)
- self.assertEqual('dwForwardProto', given_route.flags)
-
- @mock.patch('cloudinit.osys.base.get_osutils')
- @mock.patch('cloudinit.osys.windows.network.Network.routes')
- def test_set_metadata_ip_route_not_called(self, mock_routes,
- mock_osutils):
- general = mock_osutils.return_value.general
- general.check_os_version.return_value = False
-
- self._network.set_metadata_ip_route(mock.sentinel.url)
-
- self.assertFalse(mock_routes.called)
- general.check_os_version.assert_called_once_with(6, 0)
-
- @mock.patch('cloudinit.osys.base.get_osutils')
- @mock.patch('cloudinit.osys.windows.network.Network.routes')
- def test_set_metadata_ip_route_not_invalid_url(self, mock_routes,
- mock_osutils):
- general = mock_osutils.return_value.general
- general.check_os_version.return_value = True
-
- self._network.set_metadata_ip_route("http://169.253.169.253")
-
- self.assertFalse(mock_routes.called)
- general.check_os_version.assert_called_once_with(6, 0)
-
- @mock.patch('cloudinit.osys.base.get_osutils')
- @mock.patch('cloudinit.osys.windows.network.Network.routes')
- @mock.patch('cloudinit.osys.windows.network.Network.default_gateway')
- def test_set_metadata_ip_route_route_already_exists(
- self, mock_default_gateway, mock_routes, mock_osutils):
-
- mock_route = mock.Mock()
- mock_route.destination = "169.254.169.254"
- mock_routes.return_value = (mock_route, )
-
- self._network.set_metadata_ip_route("http://169.254.169.254")
-
- self.assertTrue(mock_routes.called)
- self.assertFalse(mock_default_gateway.called)
-
- @mock.patch('cloudinit.osys.base.get_osutils')
- @mock.patch('cloudinit.osys.windows.network._check_url')
- @mock.patch('cloudinit.osys.windows.network.Network.routes')
- @mock.patch('cloudinit.osys.windows.network.Network.default_gateway')
- def test_set_metadata_ip_route_route_missing_url_accessible(
- self, mock_default_gateway, mock_routes,
- mock_check_url, mock_osutils):
-
- mock_routes.return_value = ()
- mock_check_url.return_value = True
-
- self._network.set_metadata_ip_route("http://169.254.169.254")
-
- self.assertTrue(mock_routes.called)
- self.assertFalse(mock_default_gateway.called)
- self.assertTrue(mock_osutils.called)
-
- @mock.patch('cloudinit.osys.base.get_osutils')
- @mock.patch('cloudinit.osys.windows.network._check_url')
- @mock.patch('cloudinit.osys.windows.network.Network.routes')
- @mock.patch('cloudinit.osys.windows.network.Network.default_gateway')
- @mock.patch('cloudinit.osys.windows.network.Route')
- def test_set_metadata_ip_route_no_default_gateway(
- self, mock_Route, mock_default_gateway,
- mock_routes, mock_check_url, mock_osutils):
-
- mock_routes.return_value = ()
- mock_check_url.return_value = False
- mock_default_gateway.return_value = None
-
- self._network.set_metadata_ip_route("http://169.254.169.254")
-
- self.assertTrue(mock_osutils.called)
- self.assertTrue(mock_routes.called)
- self.assertTrue(mock_default_gateway.called)
- self.assertFalse(mock_Route.called)
-
- @mock.patch('cloudinit.osys.base.get_osutils')
- @mock.patch('cloudinit.osys.windows.network._check_url')
- @mock.patch('cloudinit.osys.windows.network.Network.routes')
- @mock.patch('cloudinit.osys.windows.network.Network.default_gateway')
- @mock.patch('cloudinit.osys.windows.network.Route')
- def test_set_metadata_ip_route(
- self, mock_Route, mock_default_gateway,
- mock_routes, mock_check_url, mock_osutils):
-
- mock_routes.return_value = ()
- mock_check_url.return_value = False
-
- with LogSnatcher('cloudinit.osys.windows.network') as snatcher:
- self._network.set_metadata_ip_route("http://169.254.169.254")
-
- expected = ['Setting gateway for host: 169.254.169.254']
- self.assertEqual(expected, snatcher.output)
- self.assertTrue(mock_routes.called)
- self.assertTrue(mock_default_gateway.called)
- mock_Route.assert_called_once_with(
- destination="169.254.169.254",
- netmask="255.255.255.255",
- gateway=mock_default_gateway.return_value.gateway,
- interface=None, metric=None)
- mock_Route.add.assert_called_once_with(mock_Route.return_value)
- self.assertTrue(mock_osutils.called)
diff --git a/cloudinit/tests/sources/__init__.py b/cloudinit/tests/sources/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/cloudinit/tests/sources/openstack/__init__.py b/cloudinit/tests/sources/openstack/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/cloudinit/tests/sources/openstack/test_base.py b/cloudinit/tests/sources/openstack/test_base.py
deleted file mode 100644
index d5ac11fb..00000000
--- a/cloudinit/tests/sources/openstack/test_base.py
+++ /dev/null
@@ -1,176 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-from cloudinit.sources import base as base_source
-from cloudinit.sources.openstack import base
-from cloudinit import tests
-from cloudinit.tests.util import LogSnatcher
-from cloudinit.tests.util import mock
-
-
-class TestBaseOpenStackSource(tests.TestCase):
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '__abstractmethods__', new=())
- def setUp(self):
- self._source = base.BaseOpenStackSource()
- super(TestBaseOpenStackSource, self).setUp()
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_available_versions')
- def _test_working_version(self, mock_available_versions,
- versions, expected_version):
-
- mock_available_versions.return_value = versions
-
- with LogSnatcher('cloudinit.sources.openstack.base') as snatcher:
- version = self._source._working_version()
-
- msg = "Selected version '{0}' from {1}"
- expected_logging = [msg.format(expected_version, versions)]
- self.assertEqual(expected_logging, snatcher.output)
- self.assertEqual(expected_version, version)
-
- def test_working_version_latest(self):
- self._test_working_version(versions=(), expected_version='latest')
-
- def test_working_version_other_version(self):
- versions = (
- base._OS_FOLSOM,
- base._OS_GRIZZLY,
- base._OS_HAVANA,
- )
- self._test_working_version(versions=versions,
- expected_version=base._OS_HAVANA)
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_get_meta_data')
- def test_metadata_capabilities(self, mock_get_meta_data):
- mock_get_meta_data.return_value = {
- 'uuid': mock.sentinel.id,
- 'hostname': mock.sentinel.hostname,
- 'public_keys': {'key-one': 'key-one', 'key-two': 'key-two'},
- }
-
- instance_id = self._source.instance_id()
- hostname = self._source.host_name()
- public_keys = self._source.public_keys()
-
- self.assertEqual(mock.sentinel.id, instance_id)
- self.assertEqual(mock.sentinel.hostname, hostname)
- self.assertEqual(["key-one", "key-two"], sorted(public_keys))
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_get_meta_data')
- def test_no_public_keys(self, mock_get_meta_data):
- mock_get_meta_data.return_value = {'public_keys': []}
- public_keys = self._source.public_keys()
- self.assertEqual([], public_keys)
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_get_meta_data')
- def test_admin_password(self, mock_get_meta_data):
- mock_get_meta_data.return_value = {
- 'meta': {base._ADMIN_PASSWORD: mock.sentinel.password}
- }
- password = self._source.admin_password()
- self.assertEqual(mock.sentinel.password, password)
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_path_join')
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_get_cache_data')
- def test_get_content(self, mock_get_cache_data, mock_path_join):
- result = self._source._get_content(mock.sentinel.name)
-
- mock_path_join.assert_called_once_with(
- 'openstack', 'content', mock.sentinel.name)
- mock_get_cache_data.assert_called_once_with(
- mock_path_join.return_value)
- self.assertEqual(mock_get_cache_data.return_value, result)
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_path_join')
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_get_cache_data')
- def test_user_data(self, mock_get_cache_data, mock_path_join):
- result = self._source.user_data()
-
- mock_path_join.assert_called_once_with(
- 'openstack', self._source._version, 'user_data')
- mock_get_cache_data.assert_called_once_with(
- mock_path_join.return_value)
- self.assertEqual(mock_get_cache_data.return_value.buffer, result)
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_path_join')
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_get_cache_data')
- def test_get_metadata(self, mock_get_cache_data, mock_path_join):
- mock_get_cache_data.return_value = base_source.APIResponse(b"{}")
-
- result = self._source._get_meta_data()
-
- mock_path_join.assert_called_once_with(
- 'openstack', self._source._version, 'meta_data.json')
- mock_get_cache_data.assert_called_once_with(
- mock_path_join.return_value)
- self.assertEqual({}, result)
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_path_join')
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_get_cache_data')
- def test_vendor_data(self, mock_get_cache_data, mock_path_join):
- result = self._source.vendor_data()
-
- mock_path_join.assert_called_once_with(
- 'openstack', self._source._version, 'vendor_data.json')
- mock_get_cache_data.assert_called_once_with(
- mock_path_join.return_value)
- self.assertEqual(mock_get_cache_data.return_value.buffer, result)
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_working_version')
- def test_load(self, mock_working_version):
- self._source.load()
-
- self.assertTrue(mock_working_version.called)
- self.assertEqual(mock_working_version.return_value,
- self._source._version)
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_get_meta_data')
- def test_network_config_no_config(self, mock_get_metadata):
- mock_get_metadata.return_value = {}
-
- self.assertIsNone(self._source.network_config())
-
- mock_get_metadata.return_value = {1: 2}
-
- self.assertIsNone(self._source.network_config())
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_get_meta_data')
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_get_content')
- def test_network_config(self, mock_get_content, mock_get_metadata):
- mock_get_metadata.return_value = {
- "network_config": {base._PAYLOAD_KEY: "content_path"}
- }
-
- result = self._source.network_config()
-
- mock_get_content.assert_called_once_with("content_path")
- self.assertEqual(str(mock_get_content.return_value), result)
-
- @mock.patch('cloudinit.sources.openstack.base.BaseOpenStackSource.'
- '_get_data')
- def test_get_cache_data(self, mock_get_data):
- mock_get_data.return_value = b'test'
- result = self._source._get_cache_data(mock.sentinel.path)
-
- mock_get_data.assert_called_once_with(mock.sentinel.path)
- self.assertEqual(b'test', result)
diff --git a/cloudinit/tests/sources/openstack/test_httpopenstack.py b/cloudinit/tests/sources/openstack/test_httpopenstack.py
deleted file mode 100644
index 8ec8aa0a..00000000
--- a/cloudinit/tests/sources/openstack/test_httpopenstack.py
+++ /dev/null
@@ -1,251 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import textwrap
-
-from six.moves import http_client
-
-from cloudinit import exceptions
-from cloudinit.sources import base
-from cloudinit.sources.openstack import httpopenstack
-from cloudinit import tests
-from cloudinit.tests.util import LogSnatcher
-from cloudinit.tests.util import mock
-from cloudinit import url_helper
-
-
-class TestHttpOpenStackSource(tests.TestCase):
-
- def setUp(self):
- self._source = httpopenstack.HttpOpenStackSource()
- super(TestHttpOpenStackSource, self).setUp()
-
- @mock.patch.object(httpopenstack, 'IS_WINDOWS', new=False)
- @mock.patch('cloudinit.osys.windows.network.Network.'
- 'set_metadata_ip_route')
- def test__enable_metadata_access_not_nt(self, mock_set_metadata_ip_route):
- self._source._enable_metadata_access(mock.sentinel.metadata_url)
-
- self.assertFalse(mock_set_metadata_ip_route.called)
-
- @mock.patch.object(httpopenstack, 'IS_WINDOWS', new=True)
- @mock.patch('cloudinit.osys.base.get_osutils')
- def test__enable_metadata_access_nt(self, mock_get_osutils):
-
- self._source._enable_metadata_access(mock.sentinel.metadata_url)
-
- mock_get_osutils.assert_called_once_with()
- osutils = mock_get_osutils.return_value
- osutils.network.set_metadata_ip_route.assert_called_once_with(
- mock.sentinel.metadata_url)
-
- def test__path_join(self):
- calls = [
- (('path', 'a', 'b'), 'path/a/b'),
- (('path', ), 'path'),
- (('path/', 'b/'), 'path/b/'),
- ]
- for arguments, expected in calls:
- path = self._source._path_join(*arguments)
- self.assertEqual(expected, path)
-
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._get_cache_data')
- def test__available_versions(self, mock_get_cache_data):
- mock_get_cache_data.return_value = textwrap.dedent("""
- 2013-02-02
- 2014-04-04
-
- 2015-05-05
-
- latest""")
- versions = self._source._available_versions()
- expected = ['2013-02-02', '2014-04-04', '2015-05-05', 'latest']
- mock_get_cache_data.assert_called_once_with("openstack")
- self.assertEqual(expected, versions)
-
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._get_cache_data')
- def _test__available_versions_invalid_versions(
- self, version, mock_get_cache_data):
-
- mock_get_cache_data.return_value = version
-
- exc = self.assertRaises(exceptions.CloudInitError,
- self._source._available_versions)
- expected = 'Invalid API version %r' % (version,)
- self.assertEqual(expected, str(exc))
-
- def test__available_versions_invalid_versions(self):
- versions = ['2013-no-worky', '2012', '2012-02',
- 'lates', '20004-111-222', '2004-11-11111',
- ' 2004-11-20']
- for version in versions:
- self._test__available_versions_invalid_versions(version)
-
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._get_cache_data')
- def test__available_versions_no_version_found(self, mock_get_cache_data):
- mock_get_cache_data.return_value = ''
-
- exc = self.assertRaises(exceptions.CloudInitError,
- self._source._available_versions)
- self.assertEqual('No metadata versions were found.', str(exc))
-
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._get_cache_data')
- def _test_is_password_set(self, mock_get_cache_data, data, expected):
- mock_get_cache_data.return_value = data
-
- result = self._source.is_password_set
- self.assertEqual(expected, result)
- mock_get_cache_data.assert_called_once_with(
- self._source._password_path)
-
- def test_is_password_set(self):
- empty_data = base.APIResponse(b"")
- non_empty_data = base.APIResponse(b"password")
- self._test_is_password_set(data=empty_data, expected=False)
- self._test_is_password_set(data=non_empty_data, expected=True)
-
- def _test_can_update_password(self, version, expected):
- with mock.patch.object(self._source, '_version', new=version):
- self.assertEqual(self._source.can_update_password(), expected)
-
- def test_can_update_password(self):
- self._test_can_update_password('2012-08-10', expected=False)
- self._test_can_update_password('2012-11-10', expected=False)
- self._test_can_update_password('2013-04-04', expected=True)
- self._test_can_update_password('2014-04-04', expected=True)
- self._test_can_update_password('latest', expected=False)
-
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._path_join')
- @mock.patch('cloudinit.url_helper.read_url')
- def test__post_data(self, mock_read_url, mock_path_join):
- with LogSnatcher('cloudinit.sources.openstack.'
- 'httpopenstack') as snatcher:
- self._source._post_data(mock.sentinel.path,
- mock.sentinel.data)
-
- expected_logging = [
- 'Posting metadata to: %s' % mock_path_join.return_value
- ]
- self.assertEqual(expected_logging, snatcher.output)
- mock_path_join.assert_called_once_with(
- self._source._config['metadata_url'], mock.sentinel.path)
- mock_read_url.assert_called_once_with(
- mock_path_join.return_value, data=mock.sentinel.data,
- retries=self._source._config['retries'],
- timeout=self._source._config['timeout'])
-
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._post_data')
- def test_post_password(self, mock_post_data):
- self.assertTrue(self._source.post_password(mock.sentinel.password))
- mock_post_data.assert_called_once_with(
- self._source._password_path, mock.sentinel.password)
-
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._post_data')
- def test_post_password_already_posted(self, mock_post_data):
- exc = url_helper.UrlError(None)
- exc.status_code = http_client.CONFLICT
- mock_post_data.side_effect = exc
-
- self.assertFalse(self._source.post_password(mock.sentinel.password))
- mock_post_data.assert_called_once_with(
- self._source._password_path, mock.sentinel.password)
-
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._post_data')
- def test_post_password_other_error(self, mock_post_data):
- exc = url_helper.UrlError(None)
- exc.status_code = http_client.NOT_FOUND
- mock_post_data.side_effect = exc
-
- self.assertRaises(url_helper.UrlError,
- self._source.post_password,
- mock.sentinel.password)
- mock_post_data.assert_called_once_with(
- self._source._password_path, mock.sentinel.password)
-
- @mock.patch('cloudinit.sources.openstack.base.'
- 'BaseOpenStackSource.load')
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._get_meta_data')
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._enable_metadata_access')
- def _test_load(self, mock_enable_metadata_access,
- mock_get_metadata, mock_load, expected,
- expected_logging, metadata_side_effect=None):
-
- mock_get_metadata.side_effect = metadata_side_effect
- with LogSnatcher('cloudinit.sources.openstack.'
- 'httpopenstack') as snatcher:
- response = self._source.load()
-
- self.assertEqual(expected, response)
- mock_enable_metadata_access.assert_called_once_with(
- self._source._config['metadata_url'])
- mock_load.assert_called_once_with()
- mock_get_metadata.assert_called_once_with()
- self.assertEqual(expected_logging, snatcher.output)
-
- def test_load_works(self):
- self._test_load(expected=True, expected_logging=[])
-
- def test_load_fails(self):
- expected_logging = [
- 'Metadata not found at URL %r'
- % self._source._config['metadata_url']
- ]
- self._test_load(expected=False,
- expected_logging=expected_logging,
- metadata_side_effect=ValueError)
-
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._path_join')
- @mock.patch('cloudinit.url_helper.wait_any_url')
- def test__get_data_inaccessible_metadata(self, mock_wait_any_url,
- mock_path_join):
-
- mock_wait_any_url.return_value = None
- mock_path_join.return_value = mock.sentinel.path_join
- msg = "Metadata for url {0} was not accessible in due time"
- expected = msg.format(mock.sentinel.path_join)
- expected_logging = [
- 'Getting metadata from: %s' % mock.sentinel.path_join
- ]
- with LogSnatcher('cloudinit.sources.openstack.'
- 'httpopenstack') as snatcher:
- exc = self.assertRaises(exceptions.CloudInitError,
- self._source._get_data, 'test')
-
- self.assertEqual(expected, str(exc))
- self.assertEqual(expected_logging, snatcher.output)
-
- @mock.patch('cloudinit.sources.openstack.httpopenstack.'
- 'HttpOpenStackSource._path_join')
- @mock.patch('cloudinit.url_helper.wait_any_url')
- def test__get_data(self, mock_wait_any_url, mock_path_join):
- mock_response = mock.Mock()
- response = b"test"
- mock_response.contents = response
- mock_response.encoding = 'utf-8'
-
- mock_wait_any_url.return_value = (None, mock_response)
- mock_path_join.return_value = mock.sentinel.path_join
- expected_logging = [
- 'Getting metadata from: %s' % mock.sentinel.path_join
- ]
- with LogSnatcher('cloudinit.sources.openstack.'
- 'httpopenstack') as snatcher:
- result = self._source._get_data('test')
-
- self.assertEqual(expected_logging, snatcher.output)
- self.assertIsInstance(result, base.APIResponse)
- self.assertEqual('test', str(result))
- self.assertEqual(b'test', result.buffer)
diff --git a/cloudinit/tests/sources/test_base.py b/cloudinit/tests/sources/test_base.py
deleted file mode 100644
index a39aa729..00000000
--- a/cloudinit/tests/sources/test_base.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import functools
-import string
-import types
-
-from cloudinit import exceptions
-from cloudinit import plugin_finder
-from cloudinit.sources import base
-from cloudinit.sources import strategy
-from cloudinit import tests
-
-
-class TestDataSourceDiscovery(tests.TestCase):
-
- def setUp(self):
- super(TestDataSourceDiscovery, self).setUp()
- self._modules = None
-
- @property
- def modules(self):
- if self._modules:
- return self._modules
-
- class Module(types.ModuleType):
- def data_sources(self):
- return (self, )
-
- def __call__(self):
- return self
-
- @property
- def __class__(self):
- return self
-
- modules = self._modules = list(map(Module, string.ascii_letters))
- return modules
-
- @property
- def module_iterator(self):
- modules = self.modules
-
- class ModuleIterator(plugin_finder.BaseModuleIterator):
- def list_modules(self):
- return modules + [None, "", 42]
-
- return ModuleIterator(None)
-
- def test_loader_api(self):
- # Test that the API of DataSourceLoader is sane
- loader = base.DataSourceLoader(
- names=[], module_iterator=self.module_iterator,
- strategies=[])
-
- all_data_sources = list(loader.all_data_sources())
- valid_data_sources = list(loader.valid_data_sources())
-
- self.assertEqual(all_data_sources, self.modules)
- self.assertEqual(valid_data_sources, self.modules)
-
- def test_loader_strategies(self):
- class OrdStrategy(strategy.BaseSearchStrategy):
- def search_data_sources(self, data_sources):
- return filter(lambda source: ord(source.__name__) < 100,
- data_sources)
-
- class NameStrategy(strategy.BaseSearchStrategy):
- def search_data_sources(self, data_sources):
- return (source for source in data_sources
- if source.__name__ in ('a', 'b', 'c'))
-
- loader = base.DataSourceLoader(
- names=[], module_iterator=self.module_iterator,
- strategies=(OrdStrategy(), NameStrategy(), ))
- valid_data_sources = list(loader.valid_data_sources())
-
- self.assertEqual(len(valid_data_sources), 3)
- self.assertEqual([source.__name__ for source in valid_data_sources],
- ['a', 'b', 'c'])
-
- def test_get_data_source_filtered_by_name(self):
- source = base.get_data_source(
- names=['a', 'c'],
- module_iterator=self.module_iterator.__class__)
- self.assertEqual(source.__name__, 'a')
-
- def test_get_data_source_multiple_strategies(self):
- class ReversedStrategy(strategy.BaseSearchStrategy):
- def search_data_sources(self, data_sources):
- return reversed(list(data_sources))
-
- source = base.get_data_source(
- names=['a', 'b', 'c'],
- module_iterator=self.module_iterator.__class__,
- strategies=(ReversedStrategy, ))
-
- self.assertEqual(source.__name__, 'c')
-
- def test_get_data_source_no_data_source(self):
- get_data_source = functools.partial(
- base.get_data_source,
- names=['totallymissing'],
- module_iterator=self.module_iterator.__class__)
-
- exc = self.assertRaises(exceptions.CloudInitError,
- get_data_source)
- self.assertEqual(str(exc), 'No available data source found')
-
- def test_get_data_source_no_name_filtering(self):
- source = base.get_data_source(
- names=[], module_iterator=self.module_iterator.__class__)
- self.assertEqual(source.__name__, 'a')
diff --git a/cloudinit/tests/sources/test_strategy.py b/cloudinit/tests/sources/test_strategy.py
deleted file mode 100644
index 9d84a0bc..00000000
--- a/cloudinit/tests/sources/test_strategy.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-from cloudinit.sources import strategy
-from cloudinit import tests
-from cloudinit.tests.util import mock
-
-
-class TestStrategy(tests.TestCase):
-
- def test_custom_strategy(self):
- class CustomStrategy(strategy.BaseSearchStrategy):
-
- def search_data_sources(self, data_sources):
- # Return them in reverse order
- return list(reversed(data_sources))
-
- data_sources = [mock.sentinel.first, mock.sentinel.second]
- instance = CustomStrategy()
- sources = instance.search_data_sources(data_sources)
-
- self.assertEqual(sources, [mock.sentinel.second, mock.sentinel.first])
-
- def test_is_datasource_available(self):
- class CustomStrategy(strategy.BaseSearchStrategy):
- def search_data_sources(self, _):
- pass
-
- instance = CustomStrategy()
- good_source = mock.Mock()
- good_source.load.return_value = True
- bad_source = mock.Mock()
- bad_source.load.return_value = False
-
- self.assertTrue(instance.is_datasource_available(good_source))
- self.assertFalse(instance.is_datasource_available(bad_source))
-
- def test_filter_name_strategy(self):
- names = ['first', 'second', 'third']
- full_names = names + ['fourth', 'fifth']
- sources = [type(name, (object, ), {})() for name in full_names]
- instance = strategy.FilterNameStrategy(names)
-
- sources = list(instance.search_data_sources(sources))
-
- self.assertEqual(len(sources), 3)
- self.assertEqual([source.__class__.__name__ for source in sources],
- names)
-
- def test_serial_search_strategy(self):
- def is_available(self, data_source):
- return data_source in available_sources
-
- sources = [mock.sentinel.first, mock.sentinel.second,
- mock.sentinel.third, mock.sentinel.fourth]
- available_sources = [mock.sentinel.second, mock.sentinel.fourth]
-
- with mock.patch('cloudinit.sources.strategy.BaseSearchStrategy.'
- 'is_datasource_available', new=is_available):
- instance = strategy.SerialSearchStrategy()
- valid_sources = list(instance.search_data_sources(sources))
-
- self.assertEqual(available_sources, valid_sources)
-
- def test_filter_version_strategy(self):
- class SourceV1(object):
- def version(self):
- return 'first'
-
- class SourceV2(SourceV1):
- def version(self):
- return 'second'
-
- class SourceV3(object):
- def version(self):
- return 'third'
-
- sources = [SourceV1(), SourceV2(), SourceV3()]
- instance = strategy.FilterVersionStrategy(['third', 'first'])
-
- filtered_sources = sorted(
- source.version()
- for source in instance.search_data_sources(sources))
-
- self.assertEqual(len(filtered_sources), 2)
- self.assertEqual(filtered_sources, ['first', 'third'])
-
- def test_filter_version_strategy_no_versions_given(self):
- class SourceV1(object):
- def version(self):
- return 'first'
-
- sources = [SourceV1()]
- instance = strategy.FilterVersionStrategy()
-
- filtered_sources = list(instance.search_data_sources(sources))
-
- self.assertEqual(len(filtered_sources), 0)
diff --git a/cloudinit/tests/test_plugin_finder.py b/cloudinit/tests/test_plugin_finder.py
deleted file mode 100644
index 2cb244d8..00000000
--- a/cloudinit/tests/test_plugin_finder.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import contextlib
-import os
-import shutil
-import tempfile
-
-from cloudinit import plugin_finder
-from cloudinit.tests import TestCase
-from cloudinit.tests import util
-
-
-class TestPkgutilModuleIterator(TestCase):
-
- @staticmethod
- @contextlib.contextmanager
- def _create_tmpdir():
- tmpdir = tempfile.mkdtemp()
- try:
- yield tmpdir
- finally:
- shutil.rmtree(tmpdir)
-
- @contextlib.contextmanager
- def _create_package(self):
- with self._create_tmpdir() as tmpdir:
- path = os.path.join(tmpdir, 'good.py')
- with open(path, 'w') as stream:
- stream.write('name = 42')
-
- # Make sure this fails.
- bad = os.path.join(tmpdir, 'bad.py')
- with open(bad, 'w') as stream:
- stream.write('import missingmodule')
-
- yield tmpdir
-
- def test_pkgutil_module_iterator(self):
- logging_format = ("Could not import the module 'bad' "
- "using the search path %r")
-
- with util.LogSnatcher('cloudinit.plugin_finder') as snatcher:
- with self._create_package() as tmpdir:
- expected_logging = logging_format % tmpdir
- iterator = plugin_finder.PkgutilModuleIterator([tmpdir])
- modules = list(iterator.list_modules())
-
- self.assertEqual(len(modules), 1)
- module = modules[0]
- self.assertEqual(module.name, 42)
- self.assertEqual(len(snatcher.output), 1)
- self.assertEqual(snatcher.output[0], expected_logging)
diff --git a/cloudinit/tests/test_registry.py b/cloudinit/tests/test_registry.py
deleted file mode 100644
index fdfbd8eb..00000000
--- a/cloudinit/tests/test_registry.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from cloudinit.registry import DictRegistry
-from cloudinit.tests import TestCase
-from cloudinit.tests.util import mock
-
-
-class TestDictRegistry(TestCase):
-
- def test_added_item_included_in_output(self):
- registry = DictRegistry()
- item_key, item_to_register = 'test_key', mock.Mock()
- registry.register_item(item_key, item_to_register)
- self.assertEqual({item_key: item_to_register},
- registry.registered_items)
-
- def test_registry_starts_out_empty(self):
- self.assertEqual({}, DictRegistry().registered_items)
-
- def test_modifying_registered_items_isnt_exposed_to_other_callers(self):
- registry = DictRegistry()
- registry.registered_items['test_item'] = mock.Mock()
- self.assertEqual({}, registry.registered_items)
-
- def test_keys_cannot_be_replaced(self):
- registry = DictRegistry()
- item_key = 'test_key'
- registry.register_item(item_key, mock.Mock())
- self.assertRaises(ValueError,
- registry.register_item, item_key, mock.Mock())
diff --git a/cloudinit/tests/test_reporting.py b/cloudinit/tests/test_reporting.py
deleted file mode 100644
index 922f5959..00000000
--- a/cloudinit/tests/test_reporting.py
+++ /dev/null
@@ -1,360 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-from cloudinit import reporting
-from cloudinit.reporting import handlers
-from cloudinit.tests import TestCase
-from cloudinit.tests.util import mock
-
-
-def _fake_registry():
- return mock.Mock(registered_items={'a': mock.MagicMock(),
- 'b': mock.MagicMock()})
-
-
-class TestReportStartEvent(TestCase):
-
- @mock.patch('cloudinit.reporting.instantiated_handler_registry',
- new_callable=_fake_registry)
- def test_report_start_event_passes_something_with_as_string_to_handlers(
- self, instantiated_handler_registry):
- event_name, event_description = 'my_test_event', 'my description'
- reporting.report_start_event(event_name, event_description)
- expected_string_representation = ': '.join(
- ['start', event_name, event_description])
- for _, handler in (
- instantiated_handler_registry.registered_items.items()):
- self.assertEqual(1, handler.publish_event.call_count)
- event = handler.publish_event.call_args[0][0]
- self.assertEqual(expected_string_representation, event.as_string())
-
-
-class TestReportFinishEvent(TestCase):
-
- def _report_finish_event(self, result=reporting.status.SUCCESS):
- event_name, event_description = 'my_test_event', 'my description'
- reporting.report_finish_event(
- event_name, event_description, result=result)
- return event_name, event_description
-
- def assertHandlersPassedObjectWithAsString(
- self, handlers, expected_as_string):
- for _, handler in handlers.items():
- self.assertEqual(1, handler.publish_event.call_count)
- event = handler.publish_event.call_args[0][0]
- self.assertEqual(expected_as_string, event.as_string())
-
- @mock.patch('cloudinit.reporting.instantiated_handler_registry',
- new_callable=_fake_registry)
- def test_report_finish_event_passes_something_with_as_string_to_handlers(
- self, instantiated_handler_registry):
- event_name, event_description = self._report_finish_event()
- expected_string_representation = ': '.join(
- ['finish', event_name, reporting.status.SUCCESS,
- event_description])
- self.assertHandlersPassedObjectWithAsString(
- instantiated_handler_registry.registered_items,
- expected_string_representation)
-
- @mock.patch('cloudinit.reporting.instantiated_handler_registry',
- new_callable=_fake_registry)
- def test_reporting_successful_finish_has_sensible_string_repr(
- self, instantiated_handler_registry):
- event_name, event_description = self._report_finish_event(
- result=reporting.status.SUCCESS)
- expected_string_representation = ': '.join(
- ['finish', event_name, reporting.status.SUCCESS,
- event_description])
- self.assertHandlersPassedObjectWithAsString(
- instantiated_handler_registry.registered_items,
- expected_string_representation)
-
- @mock.patch('cloudinit.reporting.instantiated_handler_registry',
- new_callable=_fake_registry)
- def test_reporting_unsuccessful_finish_has_sensible_string_repr(
- self, instantiated_handler_registry):
- event_name, event_description = self._report_finish_event(
- result=reporting.status.FAIL)
- expected_string_representation = ': '.join(
- ['finish', event_name, reporting.status.FAIL, event_description])
- self.assertHandlersPassedObjectWithAsString(
- instantiated_handler_registry.registered_items,
- expected_string_representation)
-
- def test_invalid_result_raises_attribute_error(self):
- self.assertRaises(ValueError, self._report_finish_event, ("BOGUS",))
-
-
-class TestReportingEvent(TestCase):
-
- def test_as_string(self):
- event_type, name, description = 'test_type', 'test_name', 'test_desc'
- event = reporting.ReportingEvent(event_type, name, description)
- expected_string_representation = ': '.join(
- [event_type, name, description])
- self.assertEqual(expected_string_representation, event.as_string())
-
- def test_as_dict(self):
- event_type, name, desc = 'test_type', 'test_name', 'test_desc'
- event = reporting.ReportingEvent(event_type, name, desc)
- self.assertEqual(
- {'event_type': event_type, 'name': name, 'description': desc},
- event.as_dict())
-
-
-class TestFinishReportingEvent(TestCase):
- def test_as_has_result(self):
- result = reporting.status.SUCCESS
- name, desc = 'test_name', 'test_desc'
- event = reporting.FinishReportingEvent(name, desc, result)
- ret = event.as_dict()
- self.assertTrue('result' in ret)
- self.assertEqual(ret['result'], result)
-
-
-class TestBaseReportingHandler(TestCase):
-
- def test_base_reporting_handler_is_abstract(self):
- exc = self.assertRaises(TypeError, handlers.ReportingHandler)
- self.assertIn("publish_event", str(exc))
- self.assertIn("abstract", str(exc))
-
-
-class TestLogHandler(TestCase):
-
- @mock.patch.object(reporting.handlers.logging, 'getLogger')
- def test_appropriate_logger_used(self, getLogger):
- event_type, event_name = 'test_type', 'test_name'
- event = reporting.ReportingEvent(event_type, event_name, 'description')
- reporting.handlers.LogHandler().publish_event(event)
- self.assertEqual(
- [mock.call(
- 'cloudinit.reporting.{0}.{1}'.format(event_type, event_name))],
- getLogger.call_args_list)
-
- @mock.patch.object(reporting.handlers.logging, 'getLogger')
- def test_single_log_message_at_info_published(self, getLogger):
- event = reporting.ReportingEvent('type', 'name', 'description')
- reporting.handlers.LogHandler().publish_event(event)
- self.assertEqual(1, getLogger.return_value.info.call_count)
-
- @mock.patch.object(reporting.handlers.logging, 'getLogger')
- def test_log_message_uses_event_as_string(self, getLogger):
- event = reporting.ReportingEvent('type', 'name', 'description')
- reporting.handlers.LogHandler().publish_event(event)
- self.assertIn(event.as_string(),
- getLogger.return_value.info.call_args[0][0])
-
-
-class TestDefaultRegisteredHandler(TestCase):
-
- def test_log_handler_registered_by_default(self):
- registered_items = (
- reporting.instantiated_handler_registry.registered_items)
- for _, item in registered_items.items():
- if isinstance(item, reporting.handlers.LogHandler):
- break
- else:
- self.fail('No reporting LogHandler registered by default.')
-
-
-class TestReportingConfiguration(TestCase):
-
- @mock.patch.object(reporting, 'instantiated_handler_registry')
- def test_empty_configuration_doesnt_add_handlers(
- self, instantiated_handler_registry):
- reporting.update_configuration({})
- self.assertEqual(
- 0, instantiated_handler_registry.register_item.call_count)
-
- @mock.patch.object(
- reporting, 'instantiated_handler_registry', reporting.DictRegistry())
- @mock.patch.object(reporting, 'available_handlers')
- def test_looks_up_handler_by_type_and_adds_it(self, available_handlers):
- handler_type_name = 'test_handler'
- handler_cls = mock.Mock()
- available_handlers.registered_items = {handler_type_name: handler_cls}
- handler_name = 'my_test_handler'
- reporting.update_configuration(
- {handler_name: {'type': handler_type_name}})
- self.assertEqual(
- {handler_name: handler_cls.return_value},
- reporting.instantiated_handler_registry.registered_items)
-
- @mock.patch.object(
- reporting, 'instantiated_handler_registry', reporting.DictRegistry())
- @mock.patch.object(reporting, 'available_handlers')
- def test_uses_non_type_parts_of_config_dict_as_kwargs(
- self, available_handlers):
- handler_type_name = 'test_handler'
- handler_cls = mock.Mock()
- available_handlers.registered_items = {handler_type_name: handler_cls}
- extra_kwargs = {'foo': 'bar', 'bar': 'baz'}
- handler_config = extra_kwargs.copy()
- handler_config.update({'type': handler_type_name})
- handler_name = 'my_test_handler'
- reporting.update_configuration({handler_name: handler_config})
- self.assertEqual(
- handler_cls.return_value,
- reporting.instantiated_handler_registry.registered_items[
- handler_name])
- self.assertEqual([mock.call(**extra_kwargs)],
- handler_cls.call_args_list)
-
- @mock.patch.object(
- reporting, 'instantiated_handler_registry', reporting.DictRegistry())
- @mock.patch.object(reporting, 'available_handlers')
- def test_handler_config_not_modified(self, available_handlers):
- handler_type_name = 'test_handler'
- handler_cls = mock.Mock()
- available_handlers.registered_items = {handler_type_name: handler_cls}
- handler_config = {'type': handler_type_name, 'foo': 'bar'}
- expected_handler_config = handler_config.copy()
- reporting.update_configuration({'my_test_handler': handler_config})
- self.assertEqual(expected_handler_config, handler_config)
-
- @mock.patch.object(
- reporting, 'instantiated_handler_registry', reporting.DictRegistry())
- @mock.patch.object(reporting, 'available_handlers')
- def test_handlers_removed_if_falseish_specified(self, available_handlers):
- handler_type_name = 'test_handler'
- handler_cls = mock.Mock()
- available_handlers.registered_items = {handler_type_name: handler_cls}
- handler_name = 'my_test_handler'
- reporting.update_configuration(
- {handler_name: {'type': handler_type_name}})
- self.assertEqual(
- 1, len(reporting.instantiated_handler_registry.registered_items))
- reporting.update_configuration({handler_name: None})
- self.assertEqual(
- 0, len(reporting.instantiated_handler_registry.registered_items))
-
-
-class TestReportingEventStack(TestCase):
- @mock.patch('cloudinit.reporting.report_finish_event')
- @mock.patch('cloudinit.reporting.report_start_event')
- def test_start_and_finish_success(self, report_start, report_finish):
- with reporting.ReportEventStack(name="myname", description="mydesc"):
- pass
- self.assertEqual(
- [mock.call('myname', 'mydesc')], report_start.call_args_list)
- self.assertEqual(
- [mock.call('myname', 'mydesc', reporting.status.SUCCESS)],
- report_finish.call_args_list)
-
- @mock.patch('cloudinit.reporting.report_finish_event')
- @mock.patch('cloudinit.reporting.report_start_event')
- def test_finish_exception_defaults_fail(self, report_start, report_finish):
- name = "myname"
- desc = "mydesc"
- try:
- with reporting.ReportEventStack(name, description=desc):
- raise ValueError("This didnt work")
- except ValueError:
- pass
- self.assertEqual([mock.call(name, desc)], report_start.call_args_list)
- self.assertEqual(
- [mock.call(name, desc, reporting.status.FAIL)],
- report_finish.call_args_list)
-
- @mock.patch('cloudinit.reporting.report_finish_event')
- @mock.patch('cloudinit.reporting.report_start_event')
- def test_result_on_exception_used(self, report_start, report_finish):
- name = "myname"
- desc = "mydesc"
- try:
- with reporting.ReportEventStack(
- name, desc, result_on_exception=reporting.status.WARN):
- raise ValueError("This didnt work")
- except ValueError:
- pass
- self.assertEqual([mock.call(name, desc)], report_start.call_args_list)
- self.assertEqual(
- [mock.call(name, desc, reporting.status.WARN)],
- report_finish.call_args_list)
-
- @mock.patch('cloudinit.reporting.report_start_event')
- def test_child_fullname_respects_parent(self, report_start):
- parent_name = "topname"
- c1_name = "c1name"
- c2_name = "c2name"
- c2_expected_fullname = '/'.join([parent_name, c1_name, c2_name])
- c1_expected_fullname = '/'.join([parent_name, c1_name])
-
- parent = reporting.ReportEventStack(parent_name, "topdesc")
- c1 = reporting.ReportEventStack(c1_name, "c1desc", parent=parent)
- c2 = reporting.ReportEventStack(c2_name, "c2desc", parent=c1)
- with c1:
- report_start.assert_called_with(c1_expected_fullname, "c1desc")
- with c2:
- report_start.assert_called_with(c2_expected_fullname, "c2desc")
-
- @mock.patch('cloudinit.reporting.report_finish_event')
- @mock.patch('cloudinit.reporting.report_start_event')
- def test_child_result_bubbles_up(self, report_start, report_finish):
- parent = reporting.ReportEventStack("topname", "topdesc")
- child = reporting.ReportEventStack("c_name", "c_desc", parent=parent)
- with parent:
- with child:
- child.result = reporting.status.WARN
-
- report_finish.assert_called_with(
- "topname", "topdesc", reporting.status.WARN)
-
- @mock.patch('cloudinit.reporting.report_finish_event')
- def test_message_used_in_finish(self, report_finish):
- with reporting.ReportEventStack("myname", "mydesc",
- message="mymessage"):
- pass
- self.assertEqual(
- [mock.call("myname", "mymessage", reporting.status.SUCCESS)],
- report_finish.call_args_list)
-
- @mock.patch('cloudinit.reporting.report_finish_event')
- def test_message_updatable(self, report_finish):
- with reporting.ReportEventStack("myname", "mydesc") as c:
- c.message = "all good"
- self.assertEqual(
- [mock.call("myname", "all good", reporting.status.SUCCESS)],
- report_finish.call_args_list)
-
- @mock.patch('cloudinit.reporting.report_start_event')
- @mock.patch('cloudinit.reporting.report_finish_event')
- def test_reporting_disabled_does_not_report_events(
- self, report_start, report_finish):
- with reporting.ReportEventStack("a", "b", reporting_enabled=False):
- pass
- self.assertEqual(report_start.call_count, 0)
- self.assertEqual(report_finish.call_count, 0)
-
- @mock.patch('cloudinit.reporting.report_start_event')
- @mock.patch('cloudinit.reporting.report_finish_event')
- def test_reporting_child_default_to_parent(
- self, report_start, report_finish):
- parent = reporting.ReportEventStack(
- "pname", "pdesc", reporting_enabled=False)
- child = reporting.ReportEventStack("cname", "cdesc", parent=parent)
- with parent:
- with child:
- pass
- pass
- self.assertEqual(report_start.call_count, 0)
- self.assertEqual(report_finish.call_count, 0)
-
- def test_reporting_event_has_sane_repr(self):
- myrep = reporting.ReportEventStack("fooname", "foodesc",
- reporting_enabled=True).__repr__()
- self.assertIn("fooname", myrep)
- self.assertIn("foodesc", myrep)
- self.assertIn("True", myrep)
-
- def test_set_invalid_result_raises_value_error(self):
- f = reporting.ReportEventStack("myname", "mydesc")
- self.assertRaises(ValueError, setattr, f, "result", "BOGUS")
-
-
-class TestStatusAccess(TestCase):
- def test_invalid_status_access_raises_value_error(self):
- self.assertRaises(AttributeError, getattr, reporting.status, "BOGUS")
diff --git a/cloudinit/tests/test_safeyaml.py b/cloudinit/tests/test_safeyaml.py
deleted file mode 100644
index da90d53f..00000000
--- a/cloudinit/tests/test_safeyaml.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-from cloudinit import safeyaml as yaml
-from cloudinit.tests import TestCase
-
-import tempfile
-
-
-class TestSafeYaml(TestCase):
- def test_simple(self):
- blob = '\nk1: one\nk2: two'
- expected = {'k1': "one", 'k2': "two"}
- self.assertEqual(yaml.loads(blob), expected)
-
- def test_bogus_raises_exception(self):
- badyaml = "1\n 2:"
- self.assertRaises(yaml.YAMLError, yaml.loads, badyaml)
-
- def test_unsafe_types(self):
- # should not load complex types
- unsafe_yaml = "!!python/object:__builtin__.object {}"
- self.assertRaises(yaml.YAMLError, yaml.loads, unsafe_yaml)
-
- def test_python_unicode_not_allowed(self):
- # python/unicode is not allowed
- # in the past this type was allowed, but not now, so explicit test.
- blob = "{k1: !!python/unicode 'my unicode', k2: my string}"
- self.assertRaises(yaml.YAMLError, yaml.loads, blob)
-
- def test_dumps_returns_string(self):
- self.assertTrue(
- isinstance(yaml.dumps(867 - 5309), (str,)))
-
- def test_dumps_is_loadable(self):
- mydata = {'a': 'hey', 'b': ['bee', 'Bea']}
- self.assertEqual(yaml.loads(yaml.dumps(mydata)), mydata)
-
- def test_load(self):
- valid_yaml = "foo: bar"
- expected = {'foo': 'bar'}
- with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmpf:
- tmpf.write(valid_yaml)
- tmpf.close()
- self.assertEqual(yaml.load(tmpf.name), expected)
diff --git a/cloudinit/tests/test_shell.py b/cloudinit/tests/test_shell.py
deleted file mode 100644
index 2b115862..00000000
--- a/cloudinit/tests/test_shell.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import six
-
-import cloudinit.shell as shell
-from cloudinit.tests import TestCase
-from cloudinit.tests.util import mock
-
-
-class TestMain(TestCase):
-
- def test_help_exits_success(self):
- with mock.patch('cloudinit.shell.sys.stdout'):
- exc = self.assertRaises(
- SystemExit, shell.main, args=['cloud-init', '--help'])
- self.assertEqual(exc.code, 0)
-
- def test_invalid_arguments_exit_fail(self):
- # silence writes that get to stderr
- with mock.patch('cloudinit.shell.sys.stderr'):
- exc = self.assertRaises(
- SystemExit, shell.main, args=['cloud-init', 'bogus_argument'])
- self.assertNotEqual(exc.code, 0)
-
- @mock.patch('cloudinit.shell.sys.stdout')
- def test_version_shows_cloud_init(self, mock_out_write):
- shell.main(args=['cloud-init', 'version'])
- write_arg = mock_out_write.write.call_args[0][0]
- self.assertTrue(write_arg.startswith('cloud-init'))
-
- @mock.patch('cloudinit.shell.sys.stderr', new_callable=six.StringIO)
- def test_no_arguments_shows_usage(self, stderr):
- self.assertRaises(SystemExit, shell.main, args=['cloud-init'])
- self.assertIn('usage: cloud-init', stderr.getvalue())
-
- @mock.patch('cloudinit.shell.sys.stderr', mock.MagicMock())
- def test_no_arguments_exits_2(self):
- exc = self.assertRaises(SystemExit, shell.main, args=['cloud-init'])
- self.assertEqual(2, exc.code)
-
- @mock.patch('cloudinit.shell.sys.stderr', new_callable=six.StringIO)
- def test_no_arguments_shows_error_message(self, stderr):
- self.assertRaises(SystemExit, shell.main, args=['cloud-init'])
- self.assertIn('cloud-init: error: too few arguments',
- stderr.getvalue())
-
-
-class TestLoggingConfiguration(TestCase):
-
- @mock.patch('cloudinit.shell.sys.stderr', new_callable=six.StringIO)
- def test_log_to_console(self, stderr):
- shell.main(args=['cloud-init', '--log-to-console', 'version'])
- shell.logging.getLogger().info('test log message')
- self.assertIn('test log message', stderr.getvalue())
-
- @mock.patch('cloudinit.shell.sys.stderr', new_callable=six.StringIO)
- def test_log_to_console_not_default(self, stderr):
- shell.main(args=['cloud-init', 'version'])
- shell.logging.getLogger().info('test log message')
- self.assertNotIn('test log message', stderr.getvalue())
diff --git a/cloudinit/tests/test_templating.py b/cloudinit/tests/test_templating.py
deleted file mode 100644
index e4c8ce76..00000000
--- a/cloudinit/tests/test_templating.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import fixtures
-import mock
-import os
-import textwrap
-
-from cloudinit import templater
-from cloudinit.tests import TestCase
-
-
-class TestTemplates(TestCase):
- jinja_tmpl = '\n'.join((
- "## template:jinja",
- "{{a}},{{b}}",
- ""
- ))
- jinja_params = {'a': '1', 'b': '2'}
- jinja_expected = '1,2\n'
-
- def test_render_basic(self):
- in_data = textwrap.dedent("""
- ${b}
-
- c = d
- """)
- in_data = in_data.strip()
- expected_data = textwrap.dedent("""
- 2
-
- c = d
- """)
- out_data = templater.basic_render(in_data, {'b': 2})
- self.assertEqual(expected_data.strip(), out_data)
-
- def test_render_jinja(self):
- c = templater.render_string(self.jinja_tmpl, self.jinja_params)
- self.assertEqual(self.jinja_expected, c)
-
- def test_render_jinja_crlf(self):
- blob = '\r\n'.join((
- "## template:jinja",
- "{{a}},{{b}}"))
- c = templater.render_string(blob, {"a": 1, "b": 2})
- self.assertEqual("1,2", c)
-
- def test_render_default(self):
- blob = '''$a,$b'''
- c = templater.render_string(blob, {"a": 1, "b": 2})
- self.assertEqual("1,2", c)
-
- def test_render_explict_default(self):
- blob = '\n'.join(('## template: basic', '$a,$b',))
- c = templater.render_string(blob, {"a": 1, "b": 2})
- self.assertEqual("1,2", c)
-
- def test_render_basic_deeper(self):
- hn = 'myfoohost.yahoo.com'
- expected_data = "h=%s\nc=d\n" % hn
- in_data = "h=$hostname.canonical_name\nc=d\n"
- params = {
- "hostname": {
- "canonical_name": hn,
- },
- }
- out_data = templater.render_string(in_data, params)
- self.assertEqual(expected_data, out_data)
-
- def test_render_basic_no_parens(self):
- hn = "myfoohost"
- in_data = "h=$hostname\nc=d\n"
- expected_data = "h=%s\nc=d\n" % hn
- out_data = templater.basic_render(in_data, {'hostname': hn})
- self.assertEqual(expected_data, out_data)
-
- def test_render_basic_parens(self):
- hn = "myfoohost"
- in_data = "h = ${hostname}\nc=d\n"
- expected_data = "h = %s\nc=d\n" % hn
- out_data = templater.basic_render(in_data, {'hostname': hn})
- self.assertEqual(expected_data, out_data)
-
- def test_render_basic2(self):
- mirror = "mymirror"
- codename = "zany"
- in_data = "deb $mirror $codename-updates main contrib non-free"
- ex_data = "deb %s %s-updates main contrib non-free" % (mirror,
- codename)
-
- out_data = templater.basic_render(
- in_data, {'mirror': mirror, 'codename': codename})
- self.assertEqual(ex_data, out_data)
-
- def test_render_basic_exception_1(self):
- in_data = "h=${foo.bar}"
- self.assertRaises(
- TypeError, templater.basic_render, in_data, {'foo': [1, 2]})
-
- def test_unknown_renderer_raises_exception(self):
- blob = '\n'.join((
- "## template:bigfastcat",
- "Hellow $name"
- ""))
- self.assertRaises(
- ValueError, templater.render_string, blob, {'name': 'foo'})
-
- @mock.patch.object(templater, 'JINJA_AVAILABLE', False)
- def test_jinja_without_jinja_raises_exception(self):
- blob = '\n'.join((
- "## template:jinja",
- "Hellow {{name}}"
- ""))
- templater.JINJA_AVAILABLE = False
- self.assertRaises(
- ValueError, templater.render_string, blob, {'name': 'foo'})
-
- def test_render_from_file(self):
- td = self.useFixture(fixtures.TempDir()).path
- fname = os.path.join(td, "myfile")
- with open(fname, "w") as fp:
- fp.write(self.jinja_tmpl)
- rendered = templater.render_from_file(fname, self.jinja_params)
- self.assertEqual(rendered, self.jinja_expected)
-
- def test_render_to_file(self):
- td = self.useFixture(fixtures.TempDir()).path
- src = os.path.join(td, "src")
- target = os.path.join(td, "target")
- with open(src, "w") as fp:
- fp.write(self.jinja_tmpl)
- templater.render_to_file(src, target, self.jinja_params)
- with open(target, "r") as fp:
- rendered = fp.read()
- self.assertEqual(rendered, self.jinja_expected)
diff --git a/cloudinit/tests/test_url_helper.py b/cloudinit/tests/test_url_helper.py
deleted file mode 100644
index bd1b9236..00000000
--- a/cloudinit/tests/test_url_helper.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import httpretty
-
-from cloudinit.tests import TestCase
-from cloudinit.tests.util import mock
-from cloudinit import url_helper
-
-
-class TimeJumpSideEffect(object):
-
- def __init__(self, first_time, remaining_time):
- def generator():
- yield first_time
- while True:
- yield remaining_time
-
- self.time = generator()
-
- def __call__(self):
- return next(self.time)
-
-
-class UrlHelperWaitForUrlsTest(TestCase):
-
- @httpretty.activate
- def test_url_wait_for(self):
- urls_actions = [
- ("http://www.yahoo.com", (False, False, True)),
- ("http://www.google.com", (False, False, False)),
- ]
- urls = []
- for (url, actions) in urls_actions:
- urls.append(url)
- for worked in actions:
- if worked:
- httpretty.register_uri(httpretty.GET,
- url, body=b'it worked!')
- else:
- httpretty.register_uri(httpretty.GET,
- url, body=b'no worky',
- status=400)
-
- url, response = url_helper.wait_any_url(urls)
- self.assertEqual("http://www.yahoo.com", url)
- self.assertIsInstance(response, url_helper.RequestsResponse)
- self.assertEqual(response.contents, b'it worked!')
-
- @httpretty.activate
- @mock.patch.object(
- url_helper, 'now', mock.Mock(side_effect=TimeJumpSideEffect(0, 100)))
- def test_url_wait_for_no_work(self):
-
- def request_callback(request, uri, headers):
- return (400, headers, b"no worky")
-
- urls = [
- "http://www.yahoo.com",
- "http://www.google.com",
- ]
- for url in urls:
- httpretty.register_uri(httpretty.GET,
- url, body=request_callback)
-
- self.assertIsNone(url_helper.wait_any_url(urls, max_wait=1))
-
-
-class UrlHelperFetchTest(TestCase):
-
- @httpretty.activate
- def test_url_fetch(self):
- httpretty.register_uri(httpretty.GET,
- "http://www.yahoo.com",
- body=b'it worked!')
-
- resp = url_helper.read_url("http://www.yahoo.com")
- self.assertEqual(b"it worked!", resp.contents)
- self.assertEqual(url_helper.OK, resp.status_code)
-
- @httpretty.activate
- def test_no_protocol_url(self):
- body = b'it worked!'
- no_proto = 'www.yahoo.com'
- httpretty.register_uri(httpretty.GET, "http://" + no_proto, body=body)
- resp = url_helper.read_url(no_proto)
- self.assertTrue(resp.url.startswith("http://"))
-
- @httpretty.activate
- def test_response_has_url(self):
- body = b'it worked!'
- url = 'http://www.yahoo.com/'
- httpretty.register_uri(httpretty.GET, url, body=body)
- resp = url_helper.read_url(url)
- self.assertEqual(resp.url, url)
- self.assertEqual(body, resp.contents)
-
- @httpretty.activate
- def test_retry_url_fetch(self):
- httpretty.register_uri(httpretty.GET,
- "http://www.yahoo.com",
- responses=[
- httpretty.Response(body=b"no worky",
- status=400),
- httpretty.Response(body=b"it worked!",
- status=200),
- ])
-
- resp = url_helper.read_url("http://www.yahoo.com", retries=2)
- self.assertEqual(b"it worked!", resp.contents)
- self.assertEqual(url_helper.OK, resp.status_code)
-
- @httpretty.activate
- def test_failed_url_fetch(self):
- httpretty.register_uri(httpretty.GET,
- "http://www.yahoo.com",
- body=b'no worky', status=400)
- self.assertRaises(url_helper.UrlError,
- url_helper.read_url, "http://www.yahoo.com")
-
- @httpretty.activate
- def test_failed_retry_url_fetch(self):
- httpretty.register_uri(httpretty.GET,
- "http://www.yahoo.com",
- responses=[
- httpretty.Response(body=b"no worky",
- status=400),
- httpretty.Response(body=b"no worky",
- status=400),
- httpretty.Response(body=b"no worky",
- status=400),
- ])
-
- self.assertRaises(url_helper.UrlError,
- url_helper.read_url, "http://www.yahoo.com",
- retries=2)
diff --git a/cloudinit/tests/util.py b/cloudinit/tests/util.py
deleted file mode 100644
index b1331527..00000000
--- a/cloudinit/tests/util.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import logging
-import sys
-
-try:
- from unittest import mock
-except ImportError:
- import mock # noqa
-
-
-_IS_PY26 = sys.version_info[0:2] == (2, 6)
-
-
-# This is similar with unittest.TestCase.assertLogs from Python 3.4.
-class SnatchHandler(logging.Handler):
-
- if _IS_PY26:
- # Old style junk is required on 2.6...
- def __init__(self, *args, **kwargs):
- logging.Handler.__init__(self, *args, **kwargs)
- self.output = []
- else:
- def __init__(self, *args, **kwargs):
- super(SnatchHandler, self).__init__(*args, **kwargs)
- self.output = []
-
- def emit(self, record):
- msg = self.format(record)
- self.output.append(msg)
-
-
-class LogSnatcher(object):
- """A context manager to capture emitted logged messages.
-
- The class can be used as following::
-
- with LogSnatcher('plugins.windows.createuser') as snatcher:
- LOG.info("doing stuff")
- LOG.info("doing stuff %s", 1)
- LOG.warn("doing other stuff")
- ...
- self.assertEqual(snatcher.output,
- ['INFO:unknown:doing stuff',
- 'INFO:unknown:doing stuff 1',
- 'WARN:unknown:doing other stuff'])
- """
-
- @property
- def output(self):
- """Get the output of this Snatcher.
-
- The output is a list of log messages, already formatted.
- """
- return self._snatch_handler.output
-
- def __init__(self, logger_name):
- self._logger_name = logger_name
- self._snatch_handler = SnatchHandler()
- self._logger = logging.getLogger(self._logger_name)
- self._previous_level = self._logger.getEffectiveLevel()
-
- def __enter__(self):
- self._logger.setLevel(logging.DEBUG)
- self._logger.handlers.append(self._snatch_handler)
- return self
-
- def __exit__(self, *args):
- self._logger.handlers.remove(self._snatch_handler)
- self._logger.setLevel(self._previous_level)
diff --git a/cloudinit/url_helper.py b/cloudinit/url_helper.py
deleted file mode 100644
index effeb683..00000000
--- a/cloudinit/url_helper.py
+++ /dev/null
@@ -1,307 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import time
-
-try:
- from time import monotonic as now
-except ImportError: # pragma: nocover
- from time import time as now
-
-import requests
-from requests import adapters
-from requests import exceptions
-from requests import structures
-
-# Arg, why does requests vendorize urllib3....
-from requests.packages.urllib3 import util as urllib3_util
-
-from six.moves.urllib.parse import quote as urlquote # noqa
-from six.moves.urllib.parse import urlparse # noqa
-from six.moves.urllib.parse import urlunparse # noqa
-
-from six.moves.http_client import BAD_REQUEST as _BAD_REQUEST
-from six.moves.http_client import CONFLICT # noqa
-from six.moves.http_client import MULTIPLE_CHOICES as _MULTIPLE_CHOICES
-from six.moves.http_client import OK
-
-from cloudinit import logging
-from cloudinit import version
-
-
-SSL_ENABLED = True
-try:
- import ssl as _ssl # noqa
-except ImportError:
- SSL_ENABLED = False
-
-
-LOG = logging.getLogger(__name__)
-
-
-def _get_base_url(url):
- parsed_url = list(urlparse(url, scheme='http'))
- parsed_url[2] = parsed_url[3] = parsed_url[4] = parsed_url[5] = ''
- return urlunparse(parsed_url)
-
-
-def _clean_url(url):
- parsed_url = list(urlparse(url, scheme='http'))
- if not parsed_url[1] and parsed_url[2]:
- # Swap these since this seems to be a common
- # occurrence when given urls like 'www.google.com'
- parsed_url[1] = parsed_url[2]
- parsed_url[2] = ''
- return urlunparse(parsed_url)
-
-
-class _Retry(urllib3_util.Retry):
- def is_forced_retry(self, method, status_code):
- # Allow >= 400 to be tried...
- return status_code >= _BAD_REQUEST
-
- def sleep(self):
- # The base class doesn't have a way to log what we are doing,
- # so replace it with one that does...
- backoff = self.get_backoff_time()
- if backoff <= 0:
- return
- else:
- LOG.debug("Please wait %s seconds while we wait to try again",
- backoff)
- time.sleep(backoff)
-
-
-class RequestsResponse(object):
- """A wrapper for requests responses (that provides common functions).
-
- This exists so that things like StringResponse or FileResponse can
- also exist, but with different sources of their response (aka not
- just from the requests library).
- """
-
- def __init__(self, response):
- self._response = response
-
- @property
- def contents(self):
- return self._response.content
-
- @property
- def url(self):
- return self._response.url
-
- def ok(self, redirects_ok=False):
- upper = _MULTIPLE_CHOICES
- if redirects_ok:
- upper = _BAD_REQUEST
- return self.status_code >= OK and self.status_code < upper
-
- @property
- def headers(self):
- return self._response.headers
-
- @property
- def status_code(self):
- return self._response.status_code
-
- def __str__(self):
- return self._response.text
-
-
-class UrlError(IOError):
- def __init__(self, cause, code=None, headers=None):
- super(UrlError, self).__init__(str(cause))
- self.cause = cause
- self.status_code = code
- self.headers = headers or {}
-
-
-def _get_ssl_args(url, ssl_details):
- ssl_args = {}
- scheme = urlparse(url).scheme
- if scheme == 'https' and ssl_details:
- if not SSL_ENABLED:
- LOG.warn("SSL is not supported, "
- "cert. verification can not occur!")
- else:
- if 'ca_certs' in ssl_details and ssl_details['ca_certs']:
- ssl_args['verify'] = ssl_details['ca_certs']
- else:
- ssl_args['verify'] = True
- if 'cert_file' in ssl_details and 'key_file' in ssl_details:
- ssl_args['cert'] = [ssl_details['cert_file'],
- ssl_details['key_file']]
- elif 'cert_file' in ssl_details:
- ssl_args['cert'] = str(ssl_details['cert_file'])
- return ssl_args
-
-
-def read_url(url, data=None, timeout=None, retries=0,
- headers=None, ssl_details=None,
- check_status=True, allow_redirects=True):
- """Fetch a url (or post to one) with the given options.
-
- :param url: url to fetch
- :param data:
- any data to POST (this switches the request method to POST
- instead of GET)
- :param timeout: the timeout (in seconds) to wait for a response
- :param headers: any headers to provide (and send along) in the request
- :param ssl_details:
- a dictionary containing any ssl settings, cert_file, ca_certs
- and verify are valid entries (and they are only used when the
- url provided is https)
- :param check_status:
- checks that the response status is OK after fetching (this
- ensures a exception is raised on non-OK status codes)
- :param allow_redirects: enables redirects (or disables them)
- :param retries:
- maximum number of retries to attempt when fetching the url and
- the fetch fails
- """
- url = _clean_url(url)
- request_args = {
- 'url': url,
- }
- request_args.update(_get_ssl_args(url, ssl_details))
- request_args['allow_redirects'] = allow_redirects
- request_args['method'] = 'GET'
- if timeout is not None:
- request_args['timeout'] = max(float(timeout), 0)
- if data:
- request_args['method'] = 'POST'
- request_args['data'] = data
- if not headers:
- headers = structures.CaseInsensitiveDict()
- else:
- headers = structures.CaseInsensitiveDict(headers)
- if 'User-Agent' not in headers:
- headers['User-Agent'] = 'Cloud-Init/%s' % (version.version_string())
- request_args['headers'] = headers
- session = requests.Session()
- if retries:
- retry = _Retry(total=max(int(retries), 0),
- raise_on_redirect=not allow_redirects)
- session.mount(_get_base_url(url),
- adapters.HTTPAdapter(max_retries=retry))
- try:
- with session:
- response = session.request(**request_args)
- if check_status:
- response.raise_for_status()
- except exceptions.RequestException as e:
- if e.response is not None:
- raise UrlError(e, code=e.response.status_code,
- headers=e.response.headers)
- else:
- raise UrlError(e)
- else:
- LOG.debug("Read from %s (%s, %sb)", url, response.status_code,
- len(response.content))
- return RequestsResponse(response)
-
-
-def wait_any_url(urls, max_wait=None, timeout=None,
- status_cb=None, sleep_time=1,
- exception_cb=None):
- """Wait for one of many urls to respond correctly.
-
- :param urls: a list of urls to try
- :param max_wait: roughly the maximum time to wait before giving up
- :param timeout: the timeout provided to ``read_url``
- :param status_cb:
- call method with string message when a url is not available
- :param exception_cb:
- call method with 2 arguments 'msg' (per status_cb) and
- 'exception', the exception that occurred.
- :param sleep_time: how long to sleep before trying each url again
-
- The idea of this routine is to wait for the EC2 metdata service to
- come up. On both Eucalyptus and EC2 we have seen the case where
- the instance hit the MD before the MD service was up. EC2 seems
- to have permenantely fixed this, though.
-
- In openstack, the metadata service might be painfully slow, and
- unable to avoid hitting a timeout of even up to 10 seconds or more
- (LP: #894279) for a simple GET.
-
- Offset those needs with the need to not hang forever (and block boot)
- on a system where cloud-init is configured to look for EC2 Metadata
- service but is not going to find one. It is possible that the instance
- data host (169.254.169.254) may be firewalled off Entirely for a sytem,
- meaning that the connection will block forever unless a timeout is set.
-
- This will return a tuple of the first url which succeeded and the
- response object.
- """
- start_time = now()
-
- def log_status_cb(msg, exc=None):
- LOG.debug(msg)
-
- if not status_cb:
- status_cb = log_status_cb
-
- def timeup(max_wait, start_time):
- current_time = now()
- return ((max_wait <= 0 or max_wait is None) or
- (current_time - start_time > max_wait))
-
- loop_n = 0
- while True:
- # This makes a backoff with the following graph:
- #
- # https://www.desmos.com/calculator/c8pwjy6wmt
- sleep_time = int(loop_n / 5) + 1
- for url in urls:
- current_time = now()
- if loop_n != 0:
- if timeup(max_wait, start_time):
- break
- if (timeout and
- (current_time + timeout > (start_time + max_wait))):
- # shorten timeout to not run way over max_time
- timeout = int((start_time + max_wait) - current_time)
- reason = ""
- url_exc = None
- try:
- response = read_url(url, timeout=timeout, check_status=False)
- if not response.contents:
- reason = "empty response [%s]" % (response.code)
- url_exc = UrlError(ValueError(reason), code=response.code,
- headers=response.headers)
- elif not response.ok():
- reason = "bad status code [%s]" % (response.code)
- url_exc = UrlError(ValueError(reason), code=response.code,
- headers=response.headers)
- else:
- return url, response
- except UrlError as e:
- reason = "request error [%s]" % e
- url_exc = e
- except Exception as e:
- reason = "unexpected error [%s]" % e
- url_exc = e
-
- current_time = now()
- time_taken = int(current_time - start_time)
- status_msg = "Calling '%s' failed [%s/%ss]: %s" % (url,
- time_taken,
- max_wait,
- reason)
- status_cb(status_msg)
- if exception_cb:
- exception_cb(msg=status_msg, exception=url_exc)
-
- if timeup(max_wait, start_time):
- break
-
- loop_n = loop_n + 1
- LOG.debug("Please wait %s seconds while we wait to try again",
- sleep_time)
- time.sleep(sleep_time)
-
- return None
diff --git a/cloudinit/util.py b/cloudinit/util.py
deleted file mode 100644
index 368ebeb6..00000000
--- a/cloudinit/util.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-from cloudinit import logging
-
-LOG = logging.getLogger(__name__)
-
-
-def load_file(path, encoding='utf8'):
- LOG.blather("Loading file from path '%s' (%s)", path, encoding)
- with open(path, 'rb') as fh:
- return fh.read().decode(encoding)
-
-
-class abstractclassmethod(classmethod):
- """A backport for abc.abstractclassmethod from Python 3."""
-
- __isabstractmethod__ = True
-
- def __init__(self, func):
- func.__isabstractmethod__ = True
- super(abstractclassmethod, self).__init__(func)
diff --git a/cloudinit/version.py b/cloudinit/version.py
deleted file mode 100644
index a153e67e..00000000
--- a/cloudinit/version.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-
-import pkg_resources
-
-try:
- from pbr import version as pbr_version
- _version_info = pbr_version.VersionInfo('cloudinit')
- version_string = _version_info.version_string
-except ImportError: # pragma: nocover
- _version_info = pkg_resources.get_distribution('cloudinit')
- version_string = lambda: _version_info.version
diff --git a/doc/source/api.rst b/doc/source/api.rst
deleted file mode 100644
index 85ff488c..00000000
--- a/doc/source/api.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-cloud-init Python API Documentation
-===================================
-
-.. toctree::
- :maxdepth: 2
-
- api/autoindex
diff --git a/doc/source/api/README b/doc/source/api/README
deleted file mode 100644
index 643cd1e0..00000000
--- a/doc/source/api/README
+++ /dev/null
@@ -1,4 +0,0 @@
-Don't put files in here, it's intended only for auto-generated output!
-
-Specifically, files which aren't known to git will be cleaned out of
-this directory before the docs are generated by tox.
diff --git a/doc/source/conf.py b/doc/source/conf.py
deleted file mode 100644
index 7d2cc54d..00000000
--- a/doc/source/conf.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2015 Canonical Ltd.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# vi: ts=4 expandtab
-extensions = ['sphinx.ext.autodoc']
diff --git a/doc/source/contents.rst b/doc/source/contents.rst
deleted file mode 100644
index c0615986..00000000
--- a/doc/source/contents.rst
+++ /dev/null
@@ -1,22 +0,0 @@
-.. _index:
-
-=====================
-Documentation
-=====================
-
-.. rubric:: Everything about cloud-init.
-
-
-Summary
------------------
-
-`Cloud-init`_ is the *defacto* multi-distribution package that handles
-early initialization of a cloud instance.
-
-.. toctree::
- :maxdepth: 2
-
- api
-
-
-.. _Cloud-init: https://launchpad.net/cloud-init
diff --git a/inits/systemd/cloud-config.service b/inits/systemd/cloud-config.service
deleted file mode 100644
index 41a86147..00000000
--- a/inits/systemd/cloud-config.service
+++ /dev/null
@@ -1,17 +0,0 @@
-[Unit]
-Description=Apply the settings specified in cloud-config
-After=network.target syslog.target cloud-config.target
-Requires=cloud-config.target
-Wants=network.target
-
-[Service]
-Type=oneshot
-ExecStart=/usr/bin/cloud-init modules --mode=config
-RemainAfterExit=yes
-TimeoutSec=0
-
-# Output needs to appear in instance console output
-StandardOutput=journal+console
-
-[Install]
-WantedBy=multi-user.target
diff --git a/inits/systemd/cloud-config.target b/inits/systemd/cloud-config.target
deleted file mode 100644
index 28f5bcf1..00000000
--- a/inits/systemd/cloud-config.target
+++ /dev/null
@@ -1,10 +0,0 @@
-# cloud-init normally emits a "cloud-config" upstart event to inform third
-# parties that cloud-config is available, which does us no good when we're
-# using systemd. cloud-config.target serves as this synchronization point
-# instead. Services that would "start on cloud-config" with upstart can
-# instead use "After=cloud-config.target" and "Wants=cloud-config.target"
-# as appropriate.
-
-[Unit]
-Description=Cloud-config availability
-Requires=cloud-init-local.service cloud-init.service
diff --git a/inits/systemd/cloud-final.service b/inits/systemd/cloud-final.service
deleted file mode 100644
index ef0f52b9..00000000
--- a/inits/systemd/cloud-final.service
+++ /dev/null
@@ -1,17 +0,0 @@
-[Unit]
-Description=Execute cloud user/final scripts
-After=network.target syslog.target cloud-config.service rc-local.service
-Requires=cloud-config.target
-Wants=network.target
-
-[Service]
-Type=oneshot
-ExecStart=/usr/bin/cloud-init modules --mode=final
-RemainAfterExit=yes
-TimeoutSec=0
-
-# Output needs to appear in instance console output
-StandardOutput=journal+console
-
-[Install]
-WantedBy=multi-user.target
diff --git a/inits/systemd/cloud-init-local.service b/inits/systemd/cloud-init-local.service
deleted file mode 100644
index a31985c6..00000000
--- a/inits/systemd/cloud-init-local.service
+++ /dev/null
@@ -1,16 +0,0 @@
-[Unit]
-Description=Initial cloud-init job (pre-networking)
-Wants=local-fs.target
-After=local-fs.target
-
-[Service]
-Type=oneshot
-ExecStart=/usr/bin/cloud-init init --local
-RemainAfterExit=yes
-TimeoutSec=0
-
-# Output needs to appear in instance console output
-StandardOutput=journal+console
-
-[Install]
-WantedBy=multi-user.target
diff --git a/inits/systemd/cloud-init.service b/inits/systemd/cloud-init.service
deleted file mode 100644
index 6b0c7229..00000000
--- a/inits/systemd/cloud-init.service
+++ /dev/null
@@ -1,18 +0,0 @@
-[Unit]
-Description=Initial cloud-init job (metadata service crawler)
-After=local-fs.target network.target cloud-init-local.service
-Before=sshd.service sshd-keygen.service
-Requires=network.target
-Wants=local-fs.target cloud-init-local.service sshd.service sshd-keygen.service
-
-[Service]
-Type=oneshot
-ExecStart=/usr/bin/cloud-init init
-RemainAfterExit=yes
-TimeoutSec=0
-
-# Output needs to appear in instance console output
-StandardOutput=journal+console
-
-[Install]
-WantedBy=multi-user.target
diff --git a/inits/sysvinit/debian/cloud-config b/inits/sysvinit/debian/cloud-config
deleted file mode 100644
index 53322748..00000000
--- a/inits/sysvinit/debian/cloud-config
+++ /dev/null
@@ -1,64 +0,0 @@
-#! /bin/sh
-### BEGIN INIT INFO
-# Provides: cloud-config
-# Required-Start: cloud-init cloud-init-local
-# Required-Stop:
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Cloud init modules --mode config
-# Description: Cloud configuration initialization
-### END INIT INFO
-
-# Authors: Julien Danjou
-# Juerg Haefliger
-# Thomas Goirand
-
-PATH=/sbin:/usr/sbin:/bin:/usr/bin
-DESC="Cloud service"
-NAME=cloud-init
-DAEMON=/usr/bin/$NAME
-DAEMON_ARGS="modules --mode config"
-SCRIPTNAME=/etc/init.d/$NAME
-
-# Exit if the package is not installed
-[ -x "$DAEMON" ] || exit 0
-
-# Read configuration variable file if it is present
-[ -r /etc/default/$NAME ] && . /etc/default/$NAME
-
-# Define LSB log_* functions.
-# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
-# and status_of_proc is working.
-. /lib/lsb/init-functions
-
-if init_is_upstart; then
- case "$1" in
- stop)
- exit 0
- ;;
- *)
- exit 1
- ;;
- esac
-fi
-
-case "$1" in
-start)
- log_daemon_msg "Starting $DESC" "$NAME"
- $DAEMON ${DAEMON_ARGS}
- case "$?" in
- 0|1) log_end_msg 0 ;;
- 2) log_end_msg 1 ;;
- esac
-;;
-stop|restart|force-reload)
- echo "Error: argument '$1' not supported" >&2
- exit 3
-;;
-*)
- echo "Usage: $SCRIPTNAME {start}" >&2
- exit 3
-;;
-esac
-
-:
diff --git a/inits/sysvinit/debian/cloud-final b/inits/sysvinit/debian/cloud-final
deleted file mode 100644
index 55afc8b0..00000000
--- a/inits/sysvinit/debian/cloud-final
+++ /dev/null
@@ -1,66 +0,0 @@
-#! /bin/sh
-### BEGIN INIT INFO
-# Provides: cloud-final
-# Required-Start: $all cloud-config
-# Required-Stop:
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Cloud init modules final jobs
-# Description: This runs the cloud configuration initialization "final" jobs
-# and can be seen as the traditional "rc.local" time for the cloud.
-# It runs after all cloud-config jobs are run
-### END INIT INFO
-
-# Authors: Julien Danjou
-# Juerg Haefliger
-# Thomas Goirand
-
-PATH=/sbin:/usr/sbin:/bin:/usr/bin
-DESC="Cloud service"
-NAME=cloud-init
-DAEMON=/usr/bin/$NAME
-DAEMON_ARGS="modules --mode final"
-SCRIPTNAME=/etc/init.d/$NAME
-
-# Exit if the package is not installed
-[ -x "$DAEMON" ] || exit 0
-
-# Read configuration variable file if it is present
-[ -r /etc/default/$NAME ] && . /etc/default/$NAME
-
-# Define LSB log_* functions.
-# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
-# and status_of_proc is working.
-. /lib/lsb/init-functions
-
-if init_is_upstart; then
- case "$1" in
- stop)
- exit 0
- ;;
- *)
- exit 1
- ;;
- esac
-fi
-
-case "$1" in
-start)
- log_daemon_msg "Starting $DESC" "$NAME"
- $DAEMON ${DAEMON_ARGS}
- case "$?" in
- 0|1) log_end_msg 0 ;;
- 2) log_end_msg 1 ;;
- esac
-;;
-stop|restart|force-reload)
- echo "Error: argument '$1' not supported" >&2
- exit 3
-;;
-*)
- echo "Usage: $SCRIPTNAME {start}" >&2
- exit 3
-;;
-esac
-
-:
diff --git a/inits/sysvinit/debian/cloud-init b/inits/sysvinit/debian/cloud-init
deleted file mode 100755
index 48fa0423..00000000
--- a/inits/sysvinit/debian/cloud-init
+++ /dev/null
@@ -1,64 +0,0 @@
-#! /bin/sh
-### BEGIN INIT INFO
-# Provides: cloud-init
-# Required-Start: $local_fs $remote_fs $syslog $network cloud-init-local
-# Required-Stop: $remote_fs
-# X-Start-Before: sshd
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Cloud init
-# Description: Cloud configuration initialization
-### END INIT INFO
-
-# Authors: Julien Danjou
-# Thomas Goirand
-
-PATH=/sbin:/usr/sbin:/bin:/usr/bin
-DESC="Cloud service"
-NAME=cloud-init
-DAEMON=/usr/bin/$NAME
-DAEMON_ARGS="init"
-SCRIPTNAME=/etc/init.d/$NAME
-
-# Exit if the package is not installed
-[ -x "$DAEMON" ] || exit 0
-
-# Read configuration variable file if it is present
-[ -r /etc/default/$NAME ] && . /etc/default/$NAME
-
-# Define LSB log_* functions.
-# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
-# and status_of_proc is working.
-. /lib/lsb/init-functions
-
-if init_is_upstart; then
- case "$1" in
- stop)
- exit 0
- ;;
- *)
- exit 1
- ;;
- esac
-fi
-
-case "$1" in
- start)
- log_daemon_msg "Starting $DESC" "$NAME"
- $DAEMON ${DAEMON_ARGS}
- case "$?" in
- 0|1) log_end_msg 0 ;;
- 2) log_end_msg 1 ;;
- esac
- ;;
- stop|restart|force-reload)
- echo "Error: argument '$1' not supported" >&2
- exit 3
- ;;
- *)
- echo "Usage: $SCRIPTNAME {start}" >&2
- exit 3
- ;;
-esac
-
-:
diff --git a/inits/sysvinit/debian/cloud-init-local b/inits/sysvinit/debian/cloud-init-local
deleted file mode 100644
index 802ee8e9..00000000
--- a/inits/sysvinit/debian/cloud-init-local
+++ /dev/null
@@ -1,63 +0,0 @@
-#! /bin/sh
-### BEGIN INIT INFO
-# Provides: cloud-init-local
-# Required-Start: $local_fs $remote_fs
-# Required-Stop:
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Cloud init local
-# Description: Cloud configuration initialization
-### END INIT INFO
-
-# Authors: Julien Danjou
-# Juerg Haefliger
-
-PATH=/sbin:/usr/sbin:/bin:/usr/bin
-DESC="Cloud service"
-NAME=cloud-init
-DAEMON=/usr/bin/$NAME
-DAEMON_ARGS="init --local"
-SCRIPTNAME=/etc/init.d/$NAME
-
-# Exit if the package is not installed
-[ -x "$DAEMON" ] || exit 0
-
-# Read configuration variable file if it is present
-[ -r /etc/default/$NAME ] && . /etc/default/$NAME
-
-# Define LSB log_* functions.
-# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
-# and status_of_proc is working.
-. /lib/lsb/init-functions
-
-if init_is_upstart; then
- case "$1" in
- stop)
- exit 0
- ;;
- *)
- exit 1
- ;;
- esac
-fi
-
-case "$1" in
-start)
- log_daemon_msg "Starting $DESC" "$NAME"
- $DAEMON ${DAEMON_ARGS}
- case "$?" in
- 0|1) log_end_msg 0 ;;
- 2) log_end_msg 1 ;;
- esac
-;;
-stop|restart|force-reload)
- echo "Error: argument '$1' not supported" >&2
- exit 3
-;;
-*)
- echo "Usage: $SCRIPTNAME {start}" >&2
- exit 3
-;;
-esac
-
-:
diff --git a/inits/sysvinit/freebsd/cloudconfig b/inits/sysvinit/freebsd/cloudconfig
deleted file mode 100755
index 01bc061e..00000000
--- a/inits/sysvinit/freebsd/cloudconfig
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh
-
-# PROVIDE: cloudconfig
-# REQUIRE: cloudinit cloudinitlocal
-# BEFORE: cloudfinal
-
-. /etc/rc.subr
-
-PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
-
-name="cloudconfig"
-command="/usr/local/bin/cloud-init"
-start_cmd="cloudconfig_start"
-stop_cmd=":"
-rcvar="cloudinit_enable"
-start_precmd="cloudinit_override"
-start_cmd="cloudconfig_start"
-
-cloudinit_override()
-{
- # If there exist sysconfig/defaults variable override files use it...
- if [ -f /etc/defaults/cloud-init ]; then
- . /etc/defaults/cloud-init
- fi
-}
-
-cloudconfig_start()
-{
- echo "${command} starting"
- ${command} modules --mode config
-}
-
-load_rc_config $name
-run_rc_command "$1"
diff --git a/inits/sysvinit/freebsd/cloudfinal b/inits/sysvinit/freebsd/cloudfinal
deleted file mode 100755
index 1b487aa0..00000000
--- a/inits/sysvinit/freebsd/cloudfinal
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh
-
-# PROVIDE: cloudfinal
-# REQUIRE: LOGIN cloudinit cloudconfig cloudinitlocal
-# REQUIRE: cron mail sshd swaplate
-
-. /etc/rc.subr
-
-PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
-
-name="cloudfinal"
-command="/usr/local/bin/cloud-init"
-start_cmd="cloudfinal_start"
-stop_cmd=":"
-rcvar="cloudinit_enable"
-start_precmd="cloudinit_override"
-start_cmd="cloudfinal_start"
-
-cloudinit_override()
-{
- # If there exist sysconfig/defaults variable override files use it...
- if [ -f /etc/defaults/cloud-init ]; then
- . /etc/defaults/cloud-init
- fi
-}
-
-cloudfinal_start()
-{
- echo -n "${command} starting"
- ${command} modules --mode final
-}
-
-load_rc_config $name
-run_rc_command "$1"
diff --git a/inits/sysvinit/freebsd/cloudinit b/inits/sysvinit/freebsd/cloudinit
deleted file mode 100755
index 862eeab4..00000000
--- a/inits/sysvinit/freebsd/cloudinit
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh
-
-# PROVIDE: cloudinit
-# REQUIRE: FILESYSTEMS NETWORKING cloudinitlocal
-# BEFORE: cloudconfig cloudfinal
-
-. /etc/rc.subr
-
-PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
-
-name="cloudinit"
-command="/usr/local/bin/cloud-init"
-start_cmd="cloudinit_start"
-stop_cmd=":"
-rcvar="cloudinit_enable"
-start_precmd="cloudinit_override"
-start_cmd="cloudinit_start"
-
-cloudinit_override()
-{
- # If there exist sysconfig/defaults variable override files use it...
- if [ -f /etc/defaults/cloud-init ]; then
- . /etc/defaults/cloud-init
- fi
-}
-
-cloudinit_start()
-{
- echo -n "${command} starting"
- ${command} init
-}
-
-load_rc_config $name
-run_rc_command "$1"
diff --git a/inits/sysvinit/freebsd/cloudinitlocal b/inits/sysvinit/freebsd/cloudinitlocal
deleted file mode 100755
index fb342a0f..00000000
--- a/inits/sysvinit/freebsd/cloudinitlocal
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh
-
-# PROVIDE: cloudinitlocal
-# REQUIRE: mountcritlocal
-# BEFORE: NETWORKING FILESYSTEMS cloudinit cloudconfig cloudfinal
-
-. /etc/rc.subr
-
-PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
-
-name="cloudinitlocal"
-command="/usr/local/bin/cloud-init"
-start_cmd="cloudlocal_start"
-stop_cmd=":"
-rcvar="cloudinit_enable"
-start_precmd="cloudinit_override"
-start_cmd="cloudlocal_start"
-
-cloudinit_override()
-{
- # If there exist sysconfig/defaults variable override files use it...
- if [ -f /etc/defaults/cloud-init ]; then
- . /etc/defaults/cloud-init
- fi
-}
-
-cloudlocal_start()
-{
- echo -n "${command} starting"
- ${command} init --local
-}
-
-load_rc_config $name
-run_rc_command "$1"
diff --git a/inits/sysvinit/gentoo/cloud-config b/inits/sysvinit/gentoo/cloud-config
deleted file mode 100644
index b0fa786d..00000000
--- a/inits/sysvinit/gentoo/cloud-config
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/sbin/runscript
-
-depend() {
- after cloud-init-local
- after cloud-init
- before cloud-final
- provide cloud-config
-}
-
-start() {
- cloud-init modules --mode config
- eend 0
-}
diff --git a/inits/sysvinit/gentoo/cloud-final b/inits/sysvinit/gentoo/cloud-final
deleted file mode 100644
index b457a354..00000000
--- a/inits/sysvinit/gentoo/cloud-final
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/sbin/runscript
-
-depend() {
- after cloud-config
- provide cloud-final
-}
-
-start() {
- cloud-init modules --mode final
- eend 0
-}
diff --git a/inits/sysvinit/gentoo/cloud-init b/inits/sysvinit/gentoo/cloud-init
deleted file mode 100644
index 9ab64ad8..00000000
--- a/inits/sysvinit/gentoo/cloud-init
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/sbin/runscript
-# add depends for network, dns, fs etc
-depend() {
- after cloud-init-local
- before cloud-config
- provide cloud-init
-}
-
-start() {
- cloud-init init
- eend 0
-}
diff --git a/inits/sysvinit/gentoo/cloud-init-local b/inits/sysvinit/gentoo/cloud-init-local
deleted file mode 100644
index 9d47263e..00000000
--- a/inits/sysvinit/gentoo/cloud-init-local
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/sbin/runscript
-
-depend() {
- after localmount
- after netmount
- before cloud-init
- provide cloud-init-local
-}
-
-start() {
- cloud-init init --local
- eend 0
-}
diff --git a/inits/sysvinit/redhat/cloud-config b/inits/sysvinit/redhat/cloud-config
deleted file mode 100755
index e98c3376..00000000
--- a/inits/sysvinit/redhat/cloud-config
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/bin/sh
-# Copyright 2012 Yahoo! Inc.
-# This file is part of cloud-init. See LICENCE file for license information.
-#
-# See: http://wiki.debian.org/LSBInitScripts
-# See: http://tiny.cc/czvbgw
-# See: http://www.novell.com/coolsolutions/feature/15380.html
-# Also based on dhcpd in RHEL (for comparison)
-
-### BEGIN INIT INFO
-# Provides: cloud-config
-# Required-Start: cloud-init cloud-init-local
-# Should-Start: $time
-# Required-Stop:
-# Should-Stop:
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: The config cloud-init job
-# Description: Start cloud-init and runs the config phase
-# and any associated config modules as desired.
-### END INIT INFO
-
-# Return values acc. to LSB for all commands but status:
-# 0 - success
-# 1 - generic or unspecified error
-# 2 - invalid or excess argument(s)
-# 3 - unimplemented feature (e.g. "reload")
-# 4 - user had insufficient privileges
-# 5 - program is not installed
-# 6 - program is not configured
-# 7 - program is not running
-# 8--199 - reserved (8--99 LSB, 100--149 distrib, 150--199 appl)
-#
-# Note that starting an already running service, stopping
-# or restarting a not-running service as well as the restart
-# with force-reload (in case signaling is not supported) are
-# considered a success.
-
-RETVAL=0
-
-prog="cloud-init"
-cloud_init="/usr/bin/cloud-init"
-conf="/etc/cloud/cloud.cfg"
-
-# If there exist sysconfig/default variable override files use it...
-[ -f /etc/sysconfig/cloud-init ] && . /etc/sysconfig/cloud-init
-[ -f /etc/default/cloud-init ] && . /etc/default/cloud-init
-
-start() {
- [ -x $cloud_init ] || return 5
- [ -f $conf ] || return 6
-
- echo -n $"Starting $prog: "
- $cloud_init $CLOUDINITARGS modules --mode config
- RETVAL=$?
- return $RETVAL
-}
-
-stop() {
- echo -n $"Shutting down $prog: "
- # No-op
- RETVAL=7
- return $RETVAL
-}
-
-case "$1" in
- start)
- start
- RETVAL=$?
- ;;
- stop)
- stop
- RETVAL=$?
- ;;
- restart|try-restart|condrestart)
- ## Stop the service and regardless of whether it was
- ## running or not, start it again.
- #
- ## Note: try-restart is now part of LSB (as of 1.9).
- ## RH has a similar command named condrestart.
- start
- RETVAL=$?
- ;;
- reload|force-reload)
- # It does not support reload
- RETVAL=3
- ;;
- status)
- echo -n $"Checking for service $prog:"
- # Return value is slightly different for the status command:
- # 0 - service up and running
- # 1 - service dead, but /var/run/ pid file exists
- # 2 - service dead, but /var/lock/ lock file exists
- # 3 - service not running (unused)
- # 4 - service status unknown :-(
- # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.)
- RETVAL=3
- ;;
- *)
- echo "Usage: $0 {start|stop|status|try-restart|condrestart|restart|force-reload|reload}"
- RETVAL=3
- ;;
-esac
-
-exit $RETVAL
diff --git a/inits/sysvinit/redhat/cloud-final b/inits/sysvinit/redhat/cloud-final
deleted file mode 100755
index 5c17fddc..00000000
--- a/inits/sysvinit/redhat/cloud-final
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/bin/sh
-# Copyright 2012 Yahoo! Inc.
-# This file is part of cloud-init. See LICENCE file for license information.
-
-# See: http://wiki.debian.org/LSBInitScripts
-# See: http://tiny.cc/czvbgw
-# See: http://www.novell.com/coolsolutions/feature/15380.html
-# Also based on dhcpd in RHEL (for comparison)
-
-### BEGIN INIT INFO
-# Provides: cloud-final
-# Required-Start: $all cloud-config
-# Should-Start: $time
-# Required-Stop:
-# Should-Stop:
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: The final cloud-init job
-# Description: Start cloud-init and runs the final phase
-# and any associated final modules as desired.
-### END INIT INFO
-
-# Return values acc. to LSB for all commands but status:
-# 0 - success
-# 1 - generic or unspecified error
-# 2 - invalid or excess argument(s)
-# 3 - unimplemented feature (e.g. "reload")
-# 4 - user had insufficient privileges
-# 5 - program is not installed
-# 6 - program is not configured
-# 7 - program is not running
-# 8--199 - reserved (8--99 LSB, 100--149 distrib, 150--199 appl)
-#
-# Note that starting an already running service, stopping
-# or restarting a not-running service as well as the restart
-# with force-reload (in case signaling is not supported) are
-# considered a success.
-
-RETVAL=0
-
-prog="cloud-init"
-cloud_init="/usr/bin/cloud-init"
-conf="/etc/cloud/cloud.cfg"
-
-# If there exist sysconfig/default variable override files use it...
-[ -f /etc/sysconfig/cloud-init ] && . /etc/sysconfig/cloud-init
-[ -f /etc/default/cloud-init ] && . /etc/default/cloud-init
-
-start() {
- [ -x $cloud_init ] || return 5
- [ -f $conf ] || return 6
-
- echo -n $"Starting $prog: "
- $cloud_init $CLOUDINITARGS modules --mode final
- RETVAL=$?
- return $RETVAL
-}
-
-stop() {
- echo -n $"Shutting down $prog: "
- # No-op
- RETVAL=7
- return $RETVAL
-}
-
-case "$1" in
- start)
- start
- RETVAL=$?
- ;;
- stop)
- stop
- RETVAL=$?
- ;;
- restart|try-restart|condrestart)
- ## Stop the service and regardless of whether it was
- ## running or not, start it again.
- #
- ## Note: try-restart is now part of LSB (as of 1.9).
- ## RH has a similar command named condrestart.
- start
- RETVAL=$?
- ;;
- reload|force-reload)
- # It does not support reload
- RETVAL=3
- ;;
- status)
- echo -n $"Checking for service $prog:"
- # Return value is slightly different for the status command:
- # 0 - service up and running
- # 1 - service dead, but /var/run/ pid file exists
- # 2 - service dead, but /var/lock/ lock file exists
- # 3 - service not running (unused)
- # 4 - service status unknown :-(
- # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.)
- RETVAL=3
- ;;
- *)
- echo "Usage: $0 {start|stop|status|try-restart|condrestart|restart|force-reload|reload}"
- RETVAL=3
- ;;
-esac
-
-exit $RETVAL
diff --git a/inits/sysvinit/redhat/cloud-init b/inits/sysvinit/redhat/cloud-init
deleted file mode 100755
index af8f25f6..00000000
--- a/inits/sysvinit/redhat/cloud-init
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/bin/sh
-# Copyright 2012 Yahoo! Inc.
-# This file is part of cloud-init. See LICENCE file for license information.
-
-# See: http://wiki.debian.org/LSBInitScripts
-# See: http://tiny.cc/czvbgw
-# See: http://www.novell.com/coolsolutions/feature/15380.html
-# Also based on dhcpd in RHEL (for comparison)
-
-### BEGIN INIT INFO
-# Provides: cloud-init
-# Required-Start: $local_fs $network $named $remote_fs cloud-init-local
-# Should-Start: $time
-# Required-Stop:
-# Should-Stop:
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: The initial cloud-init job (net and fs contingent)
-# Description: Start cloud-init and runs the initialization phase
-# and any associated initial modules as desired.
-### END INIT INFO
-
-# Return values acc. to LSB for all commands but status:
-# 0 - success
-# 1 - generic or unspecified error
-# 2 - invalid or excess argument(s)
-# 3 - unimplemented feature (e.g. "reload")
-# 4 - user had insufficient privileges
-# 5 - program is not installed
-# 6 - program is not configured
-# 7 - program is not running
-# 8--199 - reserved (8--99 LSB, 100--149 distrib, 150--199 appl)
-#
-# Note that starting an already running service, stopping
-# or restarting a not-running service as well as the restart
-# with force-reload (in case signaling is not supported) are
-# considered a success.
-
-RETVAL=0
-
-prog="cloud-init"
-cloud_init="/usr/bin/cloud-init"
-conf="/etc/cloud/cloud.cfg"
-
-# If there exist sysconfig/default variable override files use it...
-[ -f /etc/sysconfig/cloud-init ] && . /etc/sysconfig/cloud-init
-[ -f /etc/default/cloud-init ] && . /etc/default/cloud-init
-
-start() {
- [ -x $cloud_init ] || return 5
- [ -f $conf ] || return 6
-
- echo -n $"Starting $prog: "
- $cloud_init $CLOUDINITARGS init
- RETVAL=$?
- return $RETVAL
-}
-
-stop() {
- echo -n $"Shutting down $prog: "
- # No-op
- RETVAL=7
- return $RETVAL
-}
-
-case "$1" in
- start)
- start
- RETVAL=$?
- ;;
- stop)
- stop
- RETVAL=$?
- ;;
- restart|try-restart|condrestart)
- ## Stop the service and regardless of whether it was
- ## running or not, start it again.
- #
- ## Note: try-restart is now part of LSB (as of 1.9).
- ## RH has a similar command named condrestart.
- start
- RETVAL=$?
- ;;
- reload|force-reload)
- # It does not support reload
- RETVAL=3
- ;;
- status)
- echo -n $"Checking for service $prog:"
- # Return value is slightly different for the status command:
- # 0 - service up and running
- # 1 - service dead, but /var/run/ pid file exists
- # 2 - service dead, but /var/lock/ lock file exists
- # 3 - service not running (unused)
- # 4 - service status unknown :-(
- # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.)
- RETVAL=3
- ;;
- *)
- echo "Usage: $0 {start|stop|status|try-restart|condrestart|restart|force-reload|reload}"
- RETVAL=3
- ;;
-esac
-
-exit $RETVAL
diff --git a/inits/sysvinit/redhat/cloud-init-local b/inits/sysvinit/redhat/cloud-init-local
deleted file mode 100755
index 7d45e6fb..00000000
--- a/inits/sysvinit/redhat/cloud-init-local
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/bin/sh
-# Copyright 2012 Yahoo! Inc.
-# This file is part of cloud-init. See LICENCE file for license information.
-
-# See: http://wiki.debian.org/LSBInitScripts
-# See: http://tiny.cc/czvbgw
-# See: http://www.novell.com/coolsolutions/feature/15380.html
-# Also based on dhcpd in RHEL (for comparison)
-
-### BEGIN INIT INFO
-# Provides: cloud-init-local
-# Required-Start: $local_fs $remote_fs
-# Should-Start: $time
-# Required-Stop:
-# Should-Stop:
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: The initial cloud-init job (local fs contingent)
-# Description: Start cloud-init and runs the initialization phases
-# and any associated initial modules as desired.
-### END INIT INFO
-
-# Return values acc. to LSB for all commands but status:
-# 0 - success
-# 1 - generic or unspecified error
-# 2 - invalid or excess argument(s)
-# 3 - unimplemented feature (e.g. "reload")
-# 4 - user had insufficient privileges
-# 5 - program is not installed
-# 6 - program is not configured
-# 7 - program is not running
-# 8--199 - reserved (8--99 LSB, 100--149 distrib, 150--199 appl)
-#
-# Note that starting an already running service, stopping
-# or restarting a not-running service as well as the restart
-# with force-reload (in case signaling is not supported) are
-# considered a success.
-
-RETVAL=0
-
-prog="cloud-init"
-cloud_init="/usr/bin/cloud-init"
-conf="/etc/cloud/cloud.cfg"
-
-# If there exist sysconfig/default variable override files use it...
-[ -f /etc/sysconfig/cloud-init ] && . /etc/sysconfig/cloud-init
-[ -f /etc/default/cloud-init ] && . /etc/default/cloud-init
-
-start() {
- [ -x $cloud_init ] || return 5
- [ -f $conf ] || return 6
-
- echo -n $"Starting $prog: "
- $cloud_init $CLOUDINITARGS init --local
- RETVAL=$?
- return $RETVAL
-}
-
-stop() {
- echo -n $"Shutting down $prog: "
- # No-op
- RETVAL=7
- return $RETVAL
-}
-
-case "$1" in
- start)
- start
- RETVAL=$?
- ;;
- stop)
- stop
- RETVAL=$?
- ;;
- restart|try-restart|condrestart)
- ## Stop the service and regardless of whether it was
- ## running or not, start it again.
- #
- ## Note: try-restart is now part of LSB (as of 1.9).
- ## RH has a similar command named condrestart.
- start
- RETVAL=$?
- ;;
- reload|force-reload)
- # It does not support reload
- RETVAL=3
- ;;
- status)
- echo -n $"Checking for service $prog:"
- # Return value is slightly different for the status command:
- # 0 - service up and running
- # 1 - service dead, but /var/run/ pid file exists
- # 2 - service dead, but /var/lock/ lock file exists
- # 3 - service not running (unused)
- # 4 - service status unknown :-(
- # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.)
- RETVAL=3
- ;;
- *)
- echo "Usage: $0 {start|stop|status|try-restart|condrestart|restart|force-reload|reload}"
- RETVAL=3
- ;;
-esac
-
-exit $RETVAL
diff --git a/inits/upstart/cloud-config.conf b/inits/upstart/cloud-config.conf
deleted file mode 100644
index 2c3ef67b..00000000
--- a/inits/upstart/cloud-config.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-# cloud-config - Handle applying the settings specified in cloud-config
-description "Handle applying cloud-config"
-emits cloud-config
-
-start on (filesystem and started rsyslog)
-console output
-task
-
-exec cloud-init modules --mode=config
diff --git a/inits/upstart/cloud-final.conf b/inits/upstart/cloud-final.conf
deleted file mode 100644
index 72ae5052..00000000
--- a/inits/upstart/cloud-final.conf
+++ /dev/null
@@ -1,10 +0,0 @@
-# cloud-final.conf - run "final" jobs
-# this runs around traditional "rc.local" time.
-# and after all cloud-config jobs are run
-description "execute cloud user/final scripts"
-
-start on (stopped rc RUNLEVEL=[2345] and stopped cloud-config)
-console output
-task
-
-exec cloud-init modules --mode=final
diff --git a/inits/upstart/cloud-init-blocknet.conf b/inits/upstart/cloud-init-blocknet.conf
deleted file mode 100644
index be09e7d8..00000000
--- a/inits/upstart/cloud-init-blocknet.conf
+++ /dev/null
@@ -1,83 +0,0 @@
-# cloud-init-blocknet
-# the purpose of this job is
-# * to block networking from coming up until cloud-init-nonet has run
-# * timeout if they all do not come up in a reasonable amount of time
-description "block networking until cloud-init-local"
-start on (starting network-interface
- or starting network-manager
- or starting networking)
-stop on stopped cloud-init-local
-
-instance $JOB${INTERFACE:+/}${INTERFACE:-}
-export INTERFACE
-task
-
-script
- set +e # you cannot trap TERM reliably with 'set -e'
- SLEEP_CHILD=""
-
- static_network_up() {
- local emitted="/run/network/static-network-up-emitted"
- # /run/network/static-network-up-emitted is written by
- # upstart (via /etc/network/if-up.d/upstart). its presense would
- # indicate that static-network-up has already fired.
- [ -e "$emitted" -o -e "/var/$emitted" ]
- }
- msg() {
- local uptime="" idle="" msg=""
- if [ -r /proc/uptime ]; then
- read uptime idle < /proc/uptime
- fi
- msg="${UPSTART_INSTANCE}${uptime:+[${uptime}]}: $*"
- echo "$msg"
- }
-
- handle_sigterm() {
- # if we received sigterm and static networking is up then it probably
- # came from upstart as a result of 'stop on static-network-up'
- msg "got sigterm"
- if [ -n "$SLEEP_CHILD" ]; then
- if ! kill $SLEEP_CHILD 2>/dev/null; then
- [ ! -d "/proc/$SLEEP_CHILD" ] ||
- msg "hm.. failed to kill sleep pid $SLEEP_CHILD"
- fi
- fi
- msg "stopped"
- exit 0
- }
-
- dowait() {
- msg "blocking $1 seconds"
- # all this 'exec -a' does is get me a nicely named process in 'ps'
- # ie, 'sleep-block-network-interface.eth1'
- if [ -x /bin/bash ]; then
- bash -c 'exec -a sleep-block-$1 sleep $2' -- "$UPSTART_INSTANCE" "$1" &
- else
- sleep "$1" &
- fi
- SLEEP_CHILD=$!
- msg "sleepchild=$SLEEP_CHILD"
- wait $SLEEP_CHILD
- SLEEP_CHILD=""
- }
-
- trap handle_sigterm TERM
-
- if [ -n "$INTERFACE" -a "${INTERFACE#lo}" != "${INTERFACE}" ]; then
- msg "ignoring interface ${INTERFACE}";
- exit 0;
- fi
-
- # static_network_up already occurred
- static_network_up && { msg "static_network_up already"; exit 0; }
-
- # local-finished cloud-init-local success or failure
- lfin="/run/cloud-init/local-finished"
- disable="/etc/cloud/no-blocknet"
- [ -f "$lfin" ] && { msg "$lfin found"; exit 0; }
- [ -f "$disable" ] && { msg "$disable found"; exit 0; }
-
- dowait 120
- msg "gave up waiting for $lfin"
- exit 1
-end script
diff --git a/inits/upstart/cloud-init-container.conf b/inits/upstart/cloud-init-container.conf
deleted file mode 100644
index 6bdbe77e..00000000
--- a/inits/upstart/cloud-init-container.conf
+++ /dev/null
@@ -1,57 +0,0 @@
-# in a lxc container, events for network interfaces do not
-# get created or may be missed. This helps cloud-init-nonet along
-# by emitting those events if they have not been emitted.
-
-start on container
-stop on static-network-up
-task
-
-emits net-device-added
-
-console output
-
-script
- # if we are inside a container, then we may have to emit the ifup
- # events for 'auto' network devices.
- set -f
-
- # from /etc/network/if-up.d/upstart
- MARK_DEV_PREFIX="/run/network/ifup."
- MARK_STATIC_NETWORK_EMITTED="/run/network/static-network-up-emitted"
- # if the all static network interfaces are already up, nothing to do
- [ -f "$MARK_STATIC_NETWORK_EMITTED" ] && exit 0
-
- # ifquery will exit failure if there is no /run/network directory.
- # normally that would get created by one of network-interface.conf
- # or networking.conf. But, it is possible that we're running
- # before either of those have.
- mkdir -p /run/network
-
- # get list of all 'auto' interfaces. if there are none, nothing to do.
- auto_list=$(ifquery --list --allow auto 2>/dev/null) || :
- [ -z "$auto_list" ] && exit 0
- set -- ${auto_list}
- [ "$*" = "lo" ] && exit 0
-
- # we only want to emit for interfaces that do not exist, so filter
- # out anything that does not exist.
- for iface in "$@"; do
- [ "$iface" = "lo" ] && continue
- # skip interfaces that are already up
- [ -f "${MARK_DEV_PREFIX}${iface}" ] && continue
-
- if [ -d /sys/net ]; then
- # if /sys is mounted, and there is no /sys/net/iface, then no device
- [ -e "/sys/net/$iface" ] && continue
- else
- # sys wasn't mounted, so just check via 'ifconfig'
- ifconfig "$iface" >/dev/null 2>&1 || continue
- fi
- initctl emit --no-wait net-device-added "INTERFACE=$iface" &&
- emitted="$emitted $iface" ||
- echo "warn: ${UPSTART_JOB} failed to emit net-device-added INTERFACE=$iface"
- done
-
- [ -z "${emitted# }" ] ||
- echo "${UPSTART_JOB}: emitted ifup for ${emitted# }"
-end script
diff --git a/inits/upstart/cloud-init-local.conf b/inits/upstart/cloud-init-local.conf
deleted file mode 100644
index 5def043d..00000000
--- a/inits/upstart/cloud-init-local.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-# cloud-init - the initial cloud-init job
-# crawls metadata service, emits cloud-config
-start on mounted MOUNTPOINT=/ and mounted MOUNTPOINT=/run
-
-task
-
-console output
-
-script
- lfin=/run/cloud-init/local-finished
- ret=0
- cloud-init init --local || ret=$?
- [ -r /proc/uptime ] && read up idle < /proc/uptime || up="N/A"
- echo "$ret up $up" > "$lfin"
- exit $ret
-end script
diff --git a/inits/upstart/cloud-init-nonet.conf b/inits/upstart/cloud-init-nonet.conf
deleted file mode 100644
index 6abf6573..00000000
--- a/inits/upstart/cloud-init-nonet.conf
+++ /dev/null
@@ -1,66 +0,0 @@
-# cloud-init-no-net
-# the purpose of this job is
-# * to block running of cloud-init until all network interfaces
-# configured in /etc/network/interfaces are up
-# * timeout if they all do not come up in a reasonable amount of time
-start on mounted MOUNTPOINT=/ and stopped cloud-init-local
-stop on static-network-up
-task
-
-console output
-
-script
- set +e # you cannot trap TERM reliably with 'set -e'
- SLEEP_CHILD=""
-
- static_network_up() {
- local emitted="/run/network/static-network-up-emitted"
- # /run/network/static-network-up-emitted is written by
- # upstart (via /etc/network/if-up.d/upstart). its presense would
- # indicate that static-network-up has already fired.
- [ -e "$emitted" -o -e "/var/$emitted" ]
- }
- msg() {
- local uptime="" idle=""
- if [ -r /proc/uptime ]; then
- read uptime idle < /proc/uptime
- fi
- echo "$UPSTART_JOB${uptime:+[${uptime}]}:" "$1"
- }
-
- handle_sigterm() {
- # if we received sigterm and static networking is up then it probably
- # came from upstart as a result of 'stop on static-network-up'
- if [ -n "$SLEEP_CHILD" ]; then
- if ! kill $SLEEP_CHILD 2>/dev/null; then
- [ ! -d "/proc/$SLEEP_CHILD" ] ||
- msg "hm.. failed to kill sleep pid $SLEEP_CHILD"
- fi
- fi
- if static_network_up; then
- msg "static networking is now up"
- exit 0
- fi
- msg "recieved SIGTERM, networking not up"
- exit 2
- }
-
- dowait() {
- [ $# -eq 2 ] || msg "waiting $1 seconds for network device"
- sleep "$1" &
- SLEEP_CHILD=$!
- wait $SLEEP_CHILD
- SLEEP_CHILD=""
- }
-
- trap handle_sigterm TERM
-
- # static_network_up already occurred
- static_network_up && exit 0
-
- dowait 5 silent
- dowait 10
- dowait 115
- msg "gave up waiting for a network device."
- : > /var/lib/cloud/data/no-net
-end script
diff --git a/inits/upstart/cloud-init.conf b/inits/upstart/cloud-init.conf
deleted file mode 100644
index 41ddd284..00000000
--- a/inits/upstart/cloud-init.conf
+++ /dev/null
@@ -1,9 +0,0 @@
-# cloud-init - the initial cloud-init job
-# crawls metadata service, emits cloud-config
-start on mounted MOUNTPOINT=/ and stopped cloud-init-nonet
-
-task
-
-console output
-
-exec /usr/bin/cloud-init init
diff --git a/inits/upstart/cloud-log-shutdown.conf b/inits/upstart/cloud-log-shutdown.conf
deleted file mode 100644
index 278b9c06..00000000
--- a/inits/upstart/cloud-log-shutdown.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-# log shutdowns and reboots to the console (/dev/console)
-# this is useful for correlating logs
-start on runlevel PREVLEVEL=2
-
-task
-console output
-
-script
- # runlevel(7) says INIT_HALT will be set to HALT or POWEROFF
- date=$(date --utc)
- case "$RUNLEVEL:$INIT_HALT" in
- 6:*) mode="reboot";;
- 0:HALT) mode="halt";;
- 0:POWEROFF) mode="poweroff";;
- 0:*) mode="shutdown-unknown";;
- esac
- { read seconds idle < /proc/uptime; } 2>/dev/null || :
- echo "$date: shutting down for $mode${seconds:+ [up ${seconds%.*}s]}."
-end script
diff --git a/packages/bddeb b/packages/bddeb
deleted file mode 100755
index 9d264f92..00000000
--- a/packages/bddeb
+++ /dev/null
@@ -1,210 +0,0 @@
-#!/usr/bin/python
-
-import os
-import shutil
-import sys
-
-
-def find_root():
- # expected path is in /packages/
- top_dir = os.environ.get("CLOUD_INIT_TOP_D", None)
- if top_dir is None:
- top_dir = os.path.dirname(
- os.path.dirname(os.path.abspath(sys.argv[0])))
- if os.path.isfile(os.path.join(top_dir, 'setup.py')):
- return os.path.abspath(top_dir)
- raise OSError(("Unable to determine where your cloud-init topdir is."
- " set CLOUD_INIT_TOP_D?"))
-
-# Use the util functions from cloudinit
-sys.path.insert(0, find_root())
-
-from cloudinit import templater
-from cloudinit import util
-
-import argparse
-
-# Package names that will showup in requires to what we can actually
-# use in our debian 'control' file, this is a translation of the 'requires'
-# file pypi package name to a debian/ubuntu package name.
-PKG_MP = {
- 'argparse': 'python-argparse',
- 'cheetah': 'python-cheetah',
- 'configobj': 'python-configobj',
- 'jinja2': 'python-jinja2',
- 'jsonpatch': 'python-jsonpatch | python-json-patch',
- 'oauth': 'python-oauth',
- 'prettytable': 'python-prettytable',
- 'pyserial': 'python-serial',
- 'pyyaml': 'python-yaml',
- 'requests': 'python-requests',
-}
-DEBUILD_ARGS = ["-S", "-d"]
-
-
-def write_debian_folder(root, version, revno, append_requires=[]):
- deb_dir = util.abs_join(root, 'debian')
- os.makedirs(deb_dir)
-
- # Fill in the change log template
- templater.render_to_file(util.abs_join(find_root(),
- 'packages', 'debian', 'changelog.in'),
- util.abs_join(deb_dir, 'changelog'),
- params={
- 'version': version,
- 'revision': revno,
- })
-
- # Write out the control file template
- cmd = [util.abs_join(find_root(), 'tools', 'read-dependencies')]
- (stdout, _stderr) = util.subp(cmd)
- pkgs = [p.lower().strip() for p in stdout.splitlines()]
-
- # Map to known packages
- requires = append_requires
- for p in pkgs:
- tgt_pkg = PKG_MP.get(p)
- if not tgt_pkg:
- raise RuntimeError(("Do not know how to translate pypi dependency"
- " %r to a known package") % (p))
- else:
- requires.append(tgt_pkg)
-
- templater.render_to_file(util.abs_join(find_root(),
- 'packages', 'debian', 'control.in'),
- util.abs_join(deb_dir, 'control'),
- params={'requires': requires})
-
- # Just copy the following directly
- for base_fn in ['dirs', 'copyright', 'compat', 'rules']:
- shutil.copy(util.abs_join(find_root(),
- 'packages', 'debian', base_fn),
- util.abs_join(deb_dir, base_fn))
-
-
-def main():
-
- parser = argparse.ArgumentParser()
- parser.add_argument("-v", "--verbose", dest="verbose",
- help=("run verbosely"
- " (default: %(default)s)"),
- default=False,
- action='store_true')
- parser.add_argument("--no-cloud-utils", dest="no_cloud_utils",
- help=("don't depend on cloud-utils package"
- " (default: %(default)s)"),
- default=False,
- action='store_true')
-
- parser.add_argument("--init-system", dest="init_system",
- help=("build deb with INIT_SYSTEM=xxx"
- " (default: %(default)s"),
- default=os.environ.get("INIT_SYSTEM",
- "upstart,systemd"))
-
-
- for ent in DEBUILD_ARGS:
- parser.add_argument(ent, dest="debuild_args", action='append_const',
- const=ent, help=("pass through '%s' to debuild" % ent),
- default=[])
-
- parser.add_argument("--sign", default=False, action='store_true',
- help="sign result. do not pass -us -uc to debuild")
-
- args = parser.parse_args()
-
- if not args.sign:
- args.debuild_args.extend(['-us', '-uc'])
-
- os.environ['INIT_SYSTEM'] = args.init_system
-
- capture = True
- if args.verbose:
- capture = False
-
- with util.tempdir() as tdir:
-
- cmd = [util.abs_join(find_root(), 'tools', 'read-version')]
- (sysout, _stderr) = util.subp(cmd)
- version = sysout.strip()
-
- cmd = ['bzr', 'revno']
- (sysout, _stderr) = util.subp(cmd)
- revno = sysout.strip()
-
- # This is really only a temporary archive
- # since we will extract it then add in the debian
- # folder, then re-archive it for debian happiness
- print("Creating a temporary tarball using the 'make-tarball' helper")
- cmd = [util.abs_join(find_root(), 'tools', 'make-tarball')]
- (sysout, _stderr) = util.subp(cmd)
- arch_fn = sysout.strip()
- tmp_arch_fn = util.abs_join(tdir, os.path.basename(arch_fn))
- shutil.move(arch_fn, tmp_arch_fn)
-
- print("Extracting temporary tarball %r" % (tmp_arch_fn))
- cmd = ['tar', '-xvzf', tmp_arch_fn, '-C', tdir]
- util.subp(cmd, capture=capture)
- extracted_name = tmp_arch_fn[:-len('.tar.gz')]
- os.remove(tmp_arch_fn)
-
- xdir = util.abs_join(tdir, 'cloud-init')
- shutil.move(extracted_name, xdir)
-
- print("Creating a debian/ folder in %r" % (xdir))
- if not args.no_cloud_utils:
- append_requires=['cloud-utils | cloud-guest-utils']
- else:
- append_requires=[]
- write_debian_folder(xdir, version, revno, append_requires)
-
- # The naming here seems to follow some debian standard
- # so it will whine if it is changed...
- tar_fn = "cloud-init_%s~bzr%s.orig.tar.gz" % (version, revno)
- print("Archiving the adjusted source into %r" %
- (util.abs_join(tdir, tar_fn)))
- cmd = ['tar', '-czvf',
- util.abs_join(tdir, tar_fn),
- '-C', xdir]
- cmd.extend(os.listdir(xdir))
- util.subp(cmd, capture=capture)
-
- # Copy it locally for reference
- shutil.copy(util.abs_join(tdir, tar_fn),
- util.abs_join(os.getcwd(), tar_fn))
- print("Copied that archive to %r for local usage (if desired)." %
- (util.abs_join(os.getcwd(), tar_fn)))
-
- print("Running 'debuild %s' in %r" % (' '.join(args.debuild_args),
- xdir))
- with util.chdir(xdir):
- cmd = ['debuild', '--preserve-envvar', 'INIT_SYSTEM']
- if args.debuild_args:
- cmd.extend(args.debuild_args)
- util.subp(cmd, capture=capture)
-
- link_fn = os.path.join(os.getcwd(), 'cloud-init_all.deb')
- link_dsc = os.path.join(os.getcwd(), 'cloud-init.dsc')
- for base_fn in os.listdir(os.path.join(tdir)):
- full_fn = os.path.join(tdir, base_fn)
- if not os.path.isfile(full_fn):
- continue
- shutil.move(full_fn, base_fn)
- print("Wrote %r" % (base_fn))
- if base_fn.endswith('_all.deb'):
- # Add in the local link
- util.del_file(link_fn)
- os.symlink(base_fn, link_fn)
- print("Linked %r to %r" % (base_fn,
- os.path.basename(link_fn)))
- if base_fn.endswith('.dsc'):
- util.del_file(link_dsc)
- os.symlink(base_fn, link_dsc)
- print("Linked %r to %r" % (base_fn,
- os.path.basename(link_dsc)))
-
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/packages/brpm b/packages/brpm
deleted file mode 100755
index 9657b1dd..00000000
--- a/packages/brpm
+++ /dev/null
@@ -1,275 +0,0 @@
-#!/usr/bin/python
-
-import argparse
-import contextlib
-import glob
-import os
-import shutil
-import subprocess
-import sys
-import tempfile
-import re
-
-from datetime import datetime
-
-
-def find_root():
- # expected path is in /packages/
- top_dir = os.environ.get("CLOUD_INIT_TOP_D", None)
- if top_dir is None:
- top_dir = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
- if os.path.isfile(os.path.join(top_dir, 'setup.py')):
- return os.path.abspath(top_dir)
- raise OSError(("Unable to determine where your cloud-init topdir is."
- " set CLOUD_INIT_TOP_D?"))
-
-
-# Use the util functions from cloudinit
-sys.path.insert(0, find_root())
-
-from cloudinit import templater
-from cloudinit import util
-
-# Mapping of expected packages to there full name...
-# this is a translation of the 'requires'
-# file pypi package name to a redhat/fedora package name.
-PKG_MP = {
- 'redhat': {
- 'argparse': 'python-argparse',
- 'cheetah': 'python-cheetah',
- 'jinja2': 'python-jinja2',
- 'configobj': 'python-configobj',
- 'jsonpatch': 'python-jsonpatch',
- 'oauth': 'python-oauth',
- 'prettytable': 'python-prettytable',
- 'pyserial': 'pyserial',
- 'pyyaml': 'PyYAML',
- 'requests': 'python-requests',
- },
- 'suse': {
- 'argparse': 'python-argparse',
- 'cheetah': 'python-cheetah',
- 'configobj': 'python-configobj',
- 'jsonpatch': 'python-jsonpatch',
- 'oauth': 'python-oauth',
- 'prettytable': 'python-prettytable',
- 'pyserial': 'python-pyserial',
- 'pyyaml': 'python-yaml',
- 'requests': 'python-requests',
- }
-}
-
-# Subdirectories of the ~/rpmbuild dir
-RPM_BUILD_SUBDIRS = ['BUILD', 'RPMS', 'SOURCES', 'SPECS', 'SRPMS']
-
-
-def get_log_header(version):
- # Try to find the version in the tags output
- cmd = ['bzr', 'tags']
- (stdout, _stderr) = util.subp(cmd)
- a_rev = None
- for t in stdout.splitlines():
- ver, rev = t.split(None)
- if ver == version:
- a_rev = rev
- break
- if not a_rev:
- return None
-
- # Extract who made that tag as the header
- cmd = ['bzr', 'log', '-r%s' % (a_rev), '--timezone=utc']
- (stdout, _stderr) = util.subp(cmd)
- kvs = {
- 'comment': version,
- }
-
- for line in stdout.splitlines():
- if line.startswith('committer:'):
- kvs['who'] = line[len('committer:'):].strip()
- if line.startswith('timestamp:'):
- ts = line[len('timestamp:'):]
- ts = ts.strip()
- # http://bugs.python.org/issue6641
- ts = ts.replace("+0000", '').strip()
- ds = datetime.strptime(ts, '%a %Y-%m-%d %H:%M:%S')
- kvs['ds'] = ds
-
- return format_change_line(**kvs)
-
-
-def format_change_line(ds, who, comment=None):
- # Rpmbuild seems to be pretty strict about the date format
- d = ds.strftime("%a %b %d %Y")
- d += " - %s" % (who)
- if comment:
- d += " - %s" % (comment)
- return "* %s" % (d)
-
-
-def generate_spec_contents(args, tmpl_fn, top_dir, arc_fn):
-
- # Figure out the version and revno
- cmd = [util.abs_join(find_root(), 'tools', 'read-version')]
- (stdout, _stderr) = util.subp(cmd)
- version = stdout.strip()
-
- cmd = ['bzr', 'revno']
- (stdout, _stderr) = util.subp(cmd)
- revno = stdout.strip()
-
- # Tmpl params
- subs = {}
- subs['version'] = version
- subs['revno'] = revno
- subs['release'] = "bzr%s" % (revno)
- if args.sub_release is not None:
- subs['subrelease'] = "." + str(args.sub_release)
- else:
- subs['subrelease'] = ''
- subs['archive_name'] = arc_fn
-
- cmd = [util.abs_join(find_root(), 'tools', 'read-dependencies')]
- (stdout, _stderr) = util.subp(cmd)
- pkgs = [p.lower().strip() for p in stdout.splitlines()]
-
- # Map to known packages
- requires = []
- for p in pkgs:
- tgt_pkg = PKG_MP[args.distro].get(p)
- if not tgt_pkg:
- raise RuntimeError(("Do not know how to translate pypi dependency"
- " %r to a known package") % (p))
- else:
- requires.append(tgt_pkg)
- subs['requires'] = requires
-
- # Format a nice changelog (as best as we can)
- changelog = util.load_file(util.abs_join(find_root(), 'ChangeLog'))
- changelog_lines = []
- missing_versions = 0
- for line in changelog.splitlines():
- if not line.strip():
- continue
- if re.match(r"^\s*[\d][.][\d][.][\d]:\s*", line):
- line = line.strip(":")
- header = get_log_header(line)
- if not header:
- missing_versions += 1
- if missing_versions == 1:
- # Must be using a new 'dev'/'trunk' release
- changelog_lines.append(format_change_line(datetime.now(),
- '??'))
- else:
- sys.stderr.write(("Changelog version line %s does not "
- "have a corresponding tag!\n") % (line))
- else:
- changelog_lines.append(header)
- else:
- changelog_lines.append(line)
- subs['changelog'] = "\n".join(changelog_lines)
-
- if args.boot == 'sysvinit':
- subs['sysvinit'] = True
- else:
- subs['sysvinit'] = False
-
- if args.boot == 'systemd':
- subs['systemd'] = True
- else:
- subs['systemd'] = False
-
- subs['defines'] = ["_topdir %s" % (top_dir)]
- subs['init_sys'] = args.boot
- subs['patches'] = [os.path.basename(p) for p in args.patches]
- return templater.render_from_file(tmpl_fn, params=subs)
-
-
-def main():
-
- parser = argparse.ArgumentParser()
- parser.add_argument("-d", "--distro", dest="distro",
- help="select distro (default: %(default)s)",
- metavar="DISTRO", default='redhat',
- choices=('redhat', 'suse'))
- parser.add_argument("-b", "--boot", dest="boot",
- help="select boot type (default: %(default)s)",
- metavar="TYPE", default='sysvinit',
- choices=('sysvinit', 'systemd'))
- parser.add_argument("-v", "--verbose", dest="verbose",
- help=("run verbosely"
- " (default: %(default)s)"),
- default=False,
- action='store_true')
- parser.add_argument('-s', "--sub-release", dest="sub_release",
- metavar="RELEASE",
- help=("a 'internal' release number to concat"
- " with the bzr version number to form"
- " the final version number"),
- type=int,
- default=None)
- parser.add_argument("-p", "--patch", dest="patches",
- help=("include the following patch when building"),
- default=[],
- action='append')
- args = parser.parse_args()
- capture = True
- if args.verbose:
- capture = False
-
- # Clean out the root dir and make sure the dirs we want are in place
- root_dir = os.path.expanduser("~/rpmbuild")
- if os.path.isdir(root_dir):
- shutil.rmtree(root_dir)
-
- arc_dir = util.abs_join(root_dir, 'SOURCES')
- build_dirs = [root_dir, arc_dir]
- for dname in RPM_BUILD_SUBDIRS:
- build_dirs.append(util.abs_join(root_dir, dname))
- build_dirs.sort()
- util.ensure_dirs(build_dirs)
-
- # Archive the code
- cmd = [util.abs_join(find_root(), 'tools', 'make-tarball')]
- (stdout, _stderr) = util.subp(cmd)
- archive_fn = stdout.strip()
- real_archive_fn = os.path.join(arc_dir, os.path.basename(archive_fn))
- shutil.move(archive_fn, real_archive_fn)
- print("Archived the code in %r" % (real_archive_fn))
-
- # Form the spec file to be used
- tmpl_fn = util.abs_join(find_root(), 'packages',
- args.distro, 'cloud-init.spec.in')
- contents = generate_spec_contents(args, tmpl_fn, root_dir,
- os.path.basename(archive_fn))
- spec_fn = util.abs_join(root_dir, 'cloud-init.spec')
- util.write_file(spec_fn, contents)
- print("Created spec file at %r" % (spec_fn))
- print(contents)
- for p in args.patches:
- util.copy(p, util.abs_join(arc_dir, os.path.basename(p)))
-
- # Now build it!
- print("Running 'rpmbuild' in %r" % (root_dir))
- cmd = ['rpmbuild', '-ba', spec_fn]
- util.subp(cmd, capture=capture)
-
- # Copy the items built to our local dir
- globs = []
- globs.extend(glob.glob("%s/*.rpm" %
- (util.abs_join(root_dir, 'RPMS', 'noarch'))))
- globs.extend(glob.glob("%s/*.rpm" %
- (util.abs_join(root_dir, 'RPMS', 'x86_64'))))
- globs.extend(glob.glob("%s/*.rpm" %
- (util.abs_join(root_dir, 'RPMS'))))
- globs.extend(glob.glob("%s/*.rpm" %
- (util.abs_join(root_dir, 'SRPMS'))))
- for rpm_fn in globs:
- tgt_fn = util.abs_join(os.getcwd(), os.path.basename(rpm_fn))
- shutil.move(rpm_fn, tgt_fn)
- print("Wrote out %s package %r" % (args.distro, tgt_fn))
-
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/packages/debian/changelog.in b/packages/debian/changelog.in
deleted file mode 100644
index e3e94f54..00000000
--- a/packages/debian/changelog.in
+++ /dev/null
@@ -1,6 +0,0 @@
-## This is a cheetah template
-cloud-init (${version}~bzr${revision}-1) UNRELEASED; urgency=low
-
- * build
-
- -- Scott Moser Fri, 16 Dec 2011 11:50:25 -0500
diff --git a/packages/debian/compat b/packages/debian/compat
deleted file mode 100644
index ec635144..00000000
--- a/packages/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/packages/debian/control.in b/packages/debian/control.in
deleted file mode 100644
index 9207e5f4..00000000
--- a/packages/debian/control.in
+++ /dev/null
@@ -1,36 +0,0 @@
-## This is a cheetah template
-Source: cloud-init
-Section: admin
-Priority: optional
-Maintainer: Scott Moser
-Build-Depends: debhelper (>= 9),
- dh-python,
- dh-systemd,
- python (>= 2.6.6-3~),
- python-nose,
- pyflakes,
- python-setuptools,
- python-selinux,
- python-cheetah,
- python-mocker,
- python-httpretty,
-#for $r in $requires
- ${r},
-#end for
-XS-Python-Version: all
-Standards-Version: 3.9.3
-
-Package: cloud-init
-Architecture: all
-Depends: procps,
- python,
-#for $r in $requires
- ${r},
-#end for
- python-software-properties | software-properties-common,
- \${misc:Depends},
-Recommends: sudo
-XB-Python-Version: \${python:Versions}
-Description: Init scripts for cloud instances
- Cloud instances need special scripts to run during initialisation
- to retrieve and install ssh keys and to let the user run various scripts.
diff --git a/packages/debian/copyright b/packages/debian/copyright
deleted file mode 100644
index 5f698957..00000000
--- a/packages/debian/copyright
+++ /dev/null
@@ -1,41 +0,0 @@
-Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135
-Name: cloud-init
-Maintainer: Scott Moser
-Source: https://launchpad.net/cloud-init
-
-Upstream Author: Scott Moser
- Soren Hansen
- Chuck Short
-
-Copyright: 2010, Canonical Ltd.
-License: GPL-3 or Apache-2.0
-License: GPL-3
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 3, as
- published by the Free Software Foundation.
- .
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- .
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
- .
- The complete text of the GPL version 3 can be seen in
- /usr/share/common-licenses/GPL-3.
-License: Apache-2
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- .
- http://www.apache.org/licenses/LICENSE-2.0
- .
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- .
- On Debian-based systems the full text of the Apache version 2.0 license
- can be found in `/usr/share/common-licenses/Apache-2.0'.
diff --git a/packages/debian/dirs b/packages/debian/dirs
deleted file mode 100644
index f3de468d..00000000
--- a/packages/debian/dirs
+++ /dev/null
@@ -1,5 +0,0 @@
-var/lib/cloud
-usr/bin
-etc/init
-usr/share/doc/cloud
-etc/cloud
diff --git a/packages/debian/rules b/packages/debian/rules
deleted file mode 100755
index 9e0c5ddb..00000000
--- a/packages/debian/rules
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/make -f
-
-INIT_SYSTEM ?= upstart,systemd
-export PYBUILD_INSTALL_ARGS=--init-system=$(INIT_SYSTEM)
-
-%:
- dh $@ --with python2,systemd --buildsystem pybuild
-
-override_dh_install:
- dh_install
- install -d debian/cloud-init/etc/rsyslog.d
- cp tools/21-cloudinit.conf debian/cloud-init/etc/rsyslog.d/21-cloudinit.conf
-
-override_dh_auto_test:
- # Becuase setup tools didn't copy data...
- cp -r tests/data .pybuild/pythonX.Y_2.7/build/tests
- http_proxy= dh_auto_test -- --test-nose
diff --git a/packages/debian/watch b/packages/debian/watch
deleted file mode 100644
index 0f7a600b..00000000
--- a/packages/debian/watch
+++ /dev/null
@@ -1,2 +0,0 @@
-version=3
-https://launchpad.net/cloud-init/+download .*/\+download/cloud-init-(.+)\.tar.gz
diff --git a/packages/redhat/cloud-init.spec.in b/packages/redhat/cloud-init.spec.in
deleted file mode 100644
index 1a7001fd..00000000
--- a/packages/redhat/cloud-init.spec.in
+++ /dev/null
@@ -1,200 +0,0 @@
-## This is a cheetah template
-%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
-
-# See: http://www.zarb.org/~jasonc/macros.php
-# Or: http://fedoraproject.org/wiki/Packaging:ScriptletSnippets
-# Or: http://www.rpm.org/max-rpm/ch-rpm-inside.html
-
-#for $d in $defines
-%define ${d}
-#end for
-
-Name: cloud-init
-Version: ${version}
-Release: ${release}${subrelease}%{?dist}
-Summary: Cloud instance init scripts
-
-Group: System Environment/Base
-License: dual license GPLv3 or Apache 2.0
-URL: http://launchpad.net/cloud-init
-
-Source0: ${archive_name}
-BuildArch: noarch
-BuildRoot: %{_tmppath}
-
-BuildRequires: python-devel
-BuildRequires: python-setuptools
-BuildRequires: python-cheetah
-
-# System util packages needed
-Requires: shadow-utils
-Requires: rsyslog
-Requires: iproute
-Requires: e2fsprogs
-Requires: net-tools
-Requires: procps
-Requires: shadow-utils
-Requires: sudo >= 1.7.2p2-3
-
-# Install pypi 'dynamic' requirements
-#for $r in $requires
-Requires: ${r}
-#end for
-
-# Custom patches
-#set $size = 0
-#for $p in $patches
-Patch${size}: $p
-#set $size += 1
-#end for
-
-#if $sysvinit
-Requires(post): chkconfig
-Requires(postun): initscripts
-Requires(preun): chkconfig
-Requires(preun): initscripts
-#end if
-
-#if $systemd
-BuildRequires: systemd-units
-Requires(post): systemd-units
-Requires(postun): systemd-units
-Requires(preun): systemd-units
-#end if
-
-%description
-Cloud-init is a set of init scripts for cloud instances. Cloud instances
-need special scripts to run during initialization to retrieve and install
-ssh keys and to let the user run various scripts.
-
-%prep
-%setup -q -n %{name}-%{version}~${release}
-
-# Custom patches activation
-#set $size = 0
-#for $p in $patches
-%patch${size} -p1
-#set $size += 1
-#end for
-
-%build
-%{__python} setup.py build
-
-%install
-
-%{__python} setup.py install -O1 \
- --skip-build --root \$RPM_BUILD_ROOT \
- --init-system=${init_sys}
-
-# Note that /etc/rsyslog.d didn't exist by default until F15.
-# el6 request: https://bugzilla.redhat.com/show_bug.cgi?id=740420
-mkdir -p \$RPM_BUILD_ROOT/%{_sysconfdir}/rsyslog.d
-cp -p tools/21-cloudinit.conf \
- \$RPM_BUILD_ROOT/%{_sysconfdir}/rsyslog.d/21-cloudinit.conf
-
-# Remove the tests
-rm -rf \$RPM_BUILD_ROOT%{python_sitelib}/tests
-
-# Required dirs...
-mkdir -p \$RPM_BUILD_ROOT/%{_sharedstatedir}/cloud
-mkdir -p \$RPM_BUILD_ROOT/%{_libexecdir}/%{name}
-
-#if $systemd
-mkdir -p \$RPM_BUILD_ROOT/%{_unitdir}
-cp -p systemd/* \$RPM_BUILD_ROOT/%{_unitdir}
-#end if
-
-%clean
-rm -rf \$RPM_BUILD_ROOT
-
-%post
-
-#if $systemd
-if [ \$1 -eq 1 ]
-then
- /bin/systemctl enable cloud-config.service >/dev/null 2>&1 || :
- /bin/systemctl enable cloud-final.service >/dev/null 2>&1 || :
- /bin/systemctl enable cloud-init.service >/dev/null 2>&1 || :
- /bin/systemctl enable cloud-init-local.service >/dev/null 2>&1 || :
-fi
-#end if
-
-#if $sysvinit
-/sbin/chkconfig --add %{_initrddir}/cloud-init-local
-/sbin/chkconfig --add %{_initrddir}/cloud-init
-/sbin/chkconfig --add %{_initrddir}/cloud-config
-/sbin/chkconfig --add %{_initrddir}/cloud-final
-#end if
-
-%preun
-
-#if $sysvinit
-if [ \$1 -eq 0 ]
-then
- /sbin/service cloud-init stop >/dev/null 2>&1 || :
- /sbin/chkconfig --del cloud-init || :
- /sbin/service cloud-init-local stop >/dev/null 2>&1 || :
- /sbin/chkconfig --del cloud-init-local || :
- /sbin/service cloud-config stop >/dev/null 2>&1 || :
- /sbin/chkconfig --del cloud-config || :
- /sbin/service cloud-final stop >/dev/null 2>&1 || :
- /sbin/chkconfig --del cloud-final || :
-fi
-#end if
-
-#if $systemd
-if [ \$1 -eq 0 ]
-then
- /bin/systemctl --no-reload disable cloud-config.service >/dev/null 2>&1 || :
- /bin/systemctl --no-reload disable cloud-final.service >/dev/null 2>&1 || :
- /bin/systemctl --no-reload disable cloud-init.service >/dev/null 2>&1 || :
- /bin/systemctl --no-reload disable cloud-init-local.service >/dev/null 2>&1 || :
-fi
-#end if
-
-%postun
-
-#if $systemd
-/bin/systemctl daemon-reload >/dev/null 2>&1 || :
-#end if
-
-%files
-
-#if $sysvinit
-%attr(0755, root, root) %{_initddir}/cloud-config
-%attr(0755, root, root) %{_initddir}/cloud-final
-%attr(0755, root, root) %{_initddir}/cloud-init-local
-%attr(0755, root, root) %{_initddir}/cloud-init
-#end if
-
-#if $systemd
-%{_unitdir}/cloud-*
-#end if
-
-# Program binaries
-%{_bindir}/cloud-init*
-%{_libexecdir}/%{name}/uncloud-init
-%{_libexecdir}/%{name}/write-ssh-key-fingerprints
-
-# Docs
-%doc LICENSE ChangeLog TODO.rst requirements.txt
-%doc %{_defaultdocdir}/cloud-init/*
-
-# Configs
-%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg
-%dir %{_sysconfdir}/cloud/cloud.cfg.d
-%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/*.cfg
-%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/README
-%dir %{_sysconfdir}/cloud/templates
-%config(noreplace) %{_sysconfdir}/cloud/templates/*
-%config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf
-
-%{_libexecdir}/%{name}
-%dir %{_sharedstatedir}/cloud
-
-# Python code is here...
-%{python_sitelib}/*
-
-%changelog
-
-${changelog}
diff --git a/packages/suse/cloud-init.spec.in b/packages/suse/cloud-init.spec.in
deleted file mode 100644
index 6d0e9c54..00000000
--- a/packages/suse/cloud-init.spec.in
+++ /dev/null
@@ -1,163 +0,0 @@
-## This is a cheetah template
-
-# See: http://www.zarb.org/~jasonc/macros.php
-# Or: http://fedoraproject.org/wiki/Packaging:ScriptletSnippets
-# Or: http://www.rpm.org/max-rpm/ch-rpm-inside.html
-
-#for $d in $defines
-%define ${d}
-#end for
-
-Name: cloud-init
-Version: ${version}
-Release: ${release}${subrelease}%{?dist}
-Summary: Cloud instance init scripts
-
-Group: System/Management
-License: dual license GPLv3 or Apache 2.0
-URL: http://launchpad.net/cloud-init
-
-Source0: ${archive_name}
-BuildRoot: %{_tmppath}/%{name}-%{version}-build
-
-%if 0%{?suse_version} && 0%{?suse_version} <= 1110
-%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
-%else
-BuildArch: noarch
-%endif
-
-BuildRequires: fdupes
-BuildRequires: filesystem
-BuildRequires: python-devel
-BuildRequires: python-setuptools
-BuildRequires: python-cheetah
-
-%if 0%{?suse_version} && 0%{?suse_version} <= 1210
- %define initsys sysvinit
-%else
- %define initsys systemd
-%endif
-
-# System util packages needed
-Requires: iproute2
-Requires: e2fsprogs
-Requires: net-tools
-Requires: procps
-Requires: sudo
-
-# Install pypi 'dynamic' requirements
-#for $r in $requires
-Requires: ${r}
-#end for
-
-# Custom patches
-#set $size = 0
-#for $p in $patches
-Patch${size}: $p
-#set $size += 1
-#end for
-
-%description
-Cloud-init is a set of init scripts for cloud instances. Cloud instances
-need special scripts to run during initialization to retrieve and install
-ssh keys and to let the user run various scripts.
-
-%prep
-%setup -q -n %{name}-%{version}~${release}
-
-# Custom patches activation
-#set $size = 0
-#for $p in $patches
-%patch${size} -p1
-#set $size += 1
-#end for
-
-%build
-%{__python} setup.py build
-
-%install
-%{__python} setup.py install \
- --skip-build --root=%{buildroot} --prefix=%{_prefix} \
- --record-rpm=INSTALLED_FILES --install-lib=%{python_sitelib} \
- --init-system=%{initsys}
-
-# Remove non-SUSE templates
-rm %{buildroot}/%{_sysconfdir}/cloud/templates/*.debian.*
-rm %{buildroot}/%{_sysconfdir}/cloud/templates/*.redhat.*
-rm %{buildroot}/%{_sysconfdir}/cloud/templates/*.ubuntu.*
-
-# Remove cloud-init tests
-rm -r %{buildroot}/%{python_sitelib}/tests
-
-# Move sysvinit scripts to the correct place and create symbolic links
-%if %{initsys} == sysvinit
- mkdir -p %{buildroot}/%{_initddir}
- mv %{buildroot}%{_sysconfdir}/rc.d/init.d/* %{buildroot}%{_initddir}/
- rmdir %{buildroot}%{_sysconfdir}/rc.d/init.d
- rmdir %{buildroot}%{_sysconfdir}/rc.d
-
- mkdir -p %{buildroot}/%{_sbindir}
- pushd %{buildroot}/%{_initddir}
- for file in * ; do
- ln -s %{_initddir}/\${file} %{buildroot}/%{_sbindir}/rc\${file}
- done
- popd
-%endif
-
-# Move documentation
-mkdir -p %{buildroot}/%{_defaultdocdir}
-mv %{buildroot}/usr/share/doc/cloud-init %{buildroot}/%{_defaultdocdir}
-for doc in TODO LICENSE ChangeLog requirements.txt; do
- cp \${doc} %{buildroot}/%{_defaultdocdir}/cloud-init
-done
-
-# Remove duplicate files
-%if 0%{?suse_version}
- %fdupes %{buildroot}/%{python_sitelib}
-%endif
-
-mkdir -p %{buildroot}/var/lib/cloud
-
-%postun
-%insserv_cleanup
-
-%files
-
-# Sysvinit scripts
-%if %{initsys} == sysvinit
- %attr(0755, root, root) %{_initddir}/cloud-config
- %attr(0755, root, root) %{_initddir}/cloud-final
- %attr(0755, root, root) %{_initddir}/cloud-init-local
- %attr(0755, root, root) %{_initddir}/cloud-init
-
- %{_sbindir}/rccloud-*
-%endif
-
-# Program binaries
-%{_bindir}/cloud-init*
-
-# There doesn't seem to be an agreed upon place for these
-# although it appears the standard says /usr/lib but rpmbuild
-# will try /usr/lib64 ??
-/usr/lib/%{name}/uncloud-init
-/usr/lib/%{name}/write-ssh-key-fingerprints
-
-# Docs
-%doc %{_defaultdocdir}/cloud-init/*
-
-# Configs
-%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg
-%dir %{_sysconfdir}/cloud/cloud.cfg.d
-%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/*.cfg
-%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/README
-%dir %{_sysconfdir}/cloud/templates
-%config(noreplace) %{_sysconfdir}/cloud/templates/*
-
-# Python code is here...
-%{python_sitelib}/*
-
-/var/lib/cloud
-
-%changelog
-
-${changelog}
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 0219db9f..00000000
--- a/requirements.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-# The order of packages is significant, because pip processes them in the order
-# of appearance. Changing the order has an impact on the overall integration
-# process, which may cause wedges in the gate later.
-
-# See: https://bugs.launchpad.net/pbr/+bug/1384919 for why this is here...
-pbr>=0.11,<2.0
-
-six>=1.7.0
-pyyaml
-jsonpatch
-requests>=1.0
-requests-oauthlib
-jinja2
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index c48cd538..00000000
--- a/setup.cfg
+++ /dev/null
@@ -1,42 +0,0 @@
-[metadata]
-name = cloudinit
-version = 1.9.0
-summary = cloud initialisation magic
-description-file =
- README.rst
-author = Scott Moser
-author-email = scott.moser@canonical.com
-home-page = http://launchpad.net/cloud-init/
-classifier =
- Environment :: Console
- Environment :: Cloud
- Intended Audience :: Information Technology
- Intended Audience :: System Administrators
- License :: OSI Approved :: dual GPLv3 or Apache Software License
- Operating System :: OS Independent
- Programming Language :: Python
- Programming Language :: Python :: 2.7
- Programming Language :: Python :: 3
- Programming Language :: Python :: 3.3
-
-[files]
-packages =
- cloudinit
-
-[global]
-setup-hooks =
- pbr.hooks.setup_hook
-
-[entry_points]
-console_scripts =
- cloud-init = cloudinit.shell:main
-
-[build_sphinx]
-source-dir = doc/source
-build-dir = doc/build
-
-[pbr]
-autodoc_index_modules = 1
-autodoc_exclude_modules =
- cloudinit.osys.windows.*
-warnerrors = 1
diff --git a/setup.py b/setup.py
deleted file mode 100755
index e14585b0..00000000
--- a/setup.py
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env python
-
-import setuptools
-
-# In python < 2.7.4, a lazy loading of package `pbr` will break
-# setuptools if some other modules registered functions in `atexit`.
-# solution from: http://bugs.python.org/issue15881#msg170215
-try:
- import multiprocessing # noqa
-except ImportError:
- pass
-
-setuptools.setup(
- setup_requires=['pbr'],
- pbr=True)
diff --git a/specs/distros.rst b/specs/distros.rst
deleted file mode 100644
index 05c55351..00000000
--- a/specs/distros.rst
+++ /dev/null
@@ -1,504 +0,0 @@
-API design for the new distros namespace
-========================================
-
-API convention
---------------
-
-Before dwelving into the details of the proposed API, some conventions
-should be established, so that the API could be pythonic, easy to
-comprehend and extend. We have the following examples of how an object
-should look, depending on its state and behaviour:
-
- - Use ``.attribute`` if the attribute is not changeable
- throughout the life of the object.
- For instance, the name of a device.
-
- - Use ``.method()`` for obtaining a variant attribute, which can be
- different throughout the execution of the object and not modifiable
- through our object. This is the case for ``device.size()``, we can't
- set a new size and it can vary throughout the life of the device.
-
- - For attributes which are modifiable by us and which aren't changing
- throughout the life of the object, we could use a property-based approach.
-
- >>> device.mtu
- 1500
- # actually changing the value, not the cached value.
- >>> device.mtu = 1400
- 1400
-
-
-
-Proposed distro hierarchy
-=========================
-
-Both frameworks have a concept of Distro, each different in its way:
-
- - cloudinit has a ``distros`` location. There is a ``Distro`` base class,
- with abstract methods implemented by particular distros.
-
- Problems:
-
- * not DRY: many implementations have duplicate code with the base class
- * not properly encapsulated: distro-specific code executed outside the
- ``distros`` namespace.
- * lots of utilities, with low coherence between them.
-
- - cloudbaseinit has a ``osutils`` location. There is a ``BaseOSUtils``
- base class, with a WindowsUtils implementation.
-
- Problems:
-
- * it's a pure utilities class, leading to low coherence
- between functions.
- * it is not a namespace of OS specific functionality.
- For this, there is also ``utils.windows``.
-
-As seen, both projects lack a namespaced location for all the OS related code.
-
-The following architecture proposal tries to solve this issue, by having one
-namespace for both general utilies related to a distro, as well as distro
-specific code, which doesn't have a counterpart on other distros.
-
-It can have the following advantages:
-
- * one common place for all distro interaction, with standardized
- API for each subnamespace and increased coherence.
-
- * avoids leaky abstractions. Distro specific code goes into ``distros``
- namespace.
-
- * eases testability, it is easy to provide a mock with autospeccing
- for a namespace class, such as Route.
-
- * Pythonic API, easy to understand and use.
-
-
-The distros location is proposed, with the following structure and attributes:
-
- - The base class for a distro is found in ``distros.base``.
-
- - There are specific submodules for interaction with the OS,
- such as network, users. The submodules are part of distros namespaces,
- e.g. ``distros.windows`` should contain the modules ``network``,
- ``users`` etc.
-
- - More modules can be added, if we identify a group of interactions that can
- be categorized in one.
-
- - There should be ``general`` module, which contains general utilities that can't be moved
- in another module.
-
- - Each submodule has its own abstract base class, which must be implemented
- by each distro. Code reuse between distros is recommended.
-
- - Each submodule can expose additional behaviour that might not exist in
- the base class, if that behaviour does not make sense or if there is no
- equivalent on other platforms. But don't expose leaky abstraction, this
- specific code must be written in an abstract way, so that possible alternatives
- can be found for other distros in the mean time. This means that no ctypes
- interaction with the Windows should be exposed,
- but an object with a guaranteed interface.
-
-
- cloudinit/distros/__init__.py
- base.py
-
- freebsd/
- __init__.py
- network.py
- users.py
- general.py
- filesystem.py
- windows/
- __init__.py
- network.py
- users.py
- general.py
- ubuntu/
- __init__.py
- network.py
- ....
-
-
->>> from cloudinit.distros.base import get_distro
->>> distro = get_distro()
->>> distro.network # the actual object, not the submodule
-
->>> distro.users
-
->>> distro.general
-
-
-
-As an implementation detail, obtaining the distro object for the underlying
-distro can use a combination of `platform.system`_ and `platform.linux_distribution`_.
-
-
-In the following, I'll try to emphasize some possible APIs for each namespace.
-
-
-Network module
---------------
-
- The abstract class can look like this:
-
- class NetworkBase(ABCMeta):
-
- def routes(self):
- """Get the available routes, this can be the output of
- `netstat` on Posix and ``GetIpForwardTable`` on Windows.
- Each route should be an object encapsulating the inner workings
- of each variant.
-
- :meth:`routes` returns an object with behaviour similar to that
- of a sequence (it could be implemented using collections.Sequence
- or something similar, as long as it guarantees an interface).
- See the description of :class:`Route` for the API of the route object.
-
- The following behaviour should be supported by the object returned by
- :meth:`routes`.
-
- def __iter__(self):
- """Support iteration."""
-
- def __contains__(self, item):
- """Support containment."""
-
- def __getitem__(self, item):
- """Support element access"""
-
- Some API usages:
-
- >>> routes = network.routes()
- >>> route_object in routes
- True
- >>> '192.168.70.14' in routes
- False
- >>> route = Route.from_route_entry(
- "0.0.0.0 192.168.60.2 "
- "0.0.0.0 UG 0 0 "
- "0 eth0")
- >>> route.delete()
- """
-
- def default_gateway(self):
- """Get the default gateway.
-
- Can be implemented in the terms of :meth:`routes`.
- """
-
- def interfaces(self):
- """Get the network interfaces
-
- This can be implemented in the same vein as :meth:`routes`, e.g.
- ``sequence(Interface(...), Interface(...), ...)``
- """
-
- def firewall_rules(self):
- """Get a wrapper over the existing firewall rules.
-
- Since this seems to be only used in Windows, it can be provided
- only in the Windows utils.
- The same behaviour as for :meth:`routes` can be used, that is:
-
- >>> rules = distro.network.firewall_rules()
- # Creating a new rule.
- >>> rule = distro.network.FirewallRule(name=..., port=..., protocol=...)
- # Deleting a rule
- >>> rule.delete()
- >>> rule in rules
- >>> for rule in rules: print(rules)
- >>> rule = rules[0]
- >>> rule.name, rule.port, rule.protocol, rule.allow
-
- This gets rid of ``cloudbaseinit.osutils.firewall_add_rule`` and
- ``cloudbaseinit.osutils.firewall_remove_rule``.
- """
-
- def set_static_network_config(self, adapter_name, address, netmask,
- broadcast, gateway, dnsnameservers):
- """Configure a new static network.
-
- The :meth:``cloudinit.distros.Distro.apply_network`` should be
- removed in the favour of this method,
- which will be called by each network plugin.
- The method can be a template method, providing
- hooks for setting static DNS servers, setting static gateways or
- setting static IP addresses, which will be implemented by specific
- implementations of Distros.
- """
-
- def hosts(self):
- """Get the content of /etc/hosts file in a more OO approach.
-
-
- >>> hosts = distro.network.hosts()
- # Add a new entry in the hosts file, as well
- # in the object container itself
- >>> hosts.add(ipaddress, hostname, alias)
- # Delete an entry from the hosts file and from
- # the object container itself
- >>> hosts.delete(ipaddress, hostname, alias)
-
- This gets rid of ``cloudinit.distros.Distro.update_etc_hosts``
- and can provide support for adding a new hostname for Windows, as well.
- """
-
- class Route(object):
- """
- Encapsulate behaviour and state of a route.
- Something similar to Posix can be adopted, with the following API:
-
- route.destination
- route.gateway
- route.flags
- route.refs
- route.use
- route.netif -> instance of :class:`Interface` object
- route.expire
- route.static -> 'S' in self.flags
- route.usable -> 'U' in self.flag
-
- This can use a namedtuple as a base, but this should
- be considered an implementation detail by the users
- of this class.
- """
-
- @classmethod
- def from_route_item(self, item):
- """
- Build a Route from a routing entry, either from
- the output of `netstat` or what will be used on Posix or
- from `GetIpForwardTable`.
- """
-
- class Interface(object):
- """Encapsulation for the state and behaviour of an interface.
-
- This method gets rid of ``cloudbaseinit.osutils.get_network_adapters``
- and with the following behaviour
- it gets rid of ``cloudinit.distros._bring_up_interface``:
-
- >>> interfaces = distro.network.interfaces()
- >>> interface = interfaces[0]
- >>> interface.up()
- >>> interface.down()
- >>> interface.is_up()
- # Change mtu for this interface
- >>> interface.mtu = 1400
- # Get interface mtu
- >>> interface.mtu
- 1400
-
- If we have only the name of an interface, we should be able to
- obtain a :class:`Interface` instance from it.
-
- >>> interface = distro.network.Interface.from_name('eth0')
- >>> interface = distro.network.Interface.from_mac( u'00:50:56:C0:00:01')
-
- Each Distro specific implementation of :class:`Interface` should
- be exported in the `network` module as the `Interface` attribute,
- so that the underlying OS is completely hidden from an API point-of-view.
- """
-
- # alternative constructors
-
- @classmethod
- def from_name(cls, name):
- # return a new Interface
-
- @classmethod
- def from_mac(self, mac):
- # return a new Interface
-
- # Actual methods for behaviour
-
- def up(self):
- """Activate the interface."""
-
- def down(self):
- """Deactivate the interface."""
-
- def is_up(self):
- """Check if the interface is activated."""
-
- # Other getters and setter for what can be changed for an
- # interface, such as the mtu.
-
- @property
- def mtu(self):
- pass
-
- @mtu.setter
- def mtu(self, value):
- pass
-
- # Other read only attributes, such as ``.name``, ``.mac`` etc.
-
- .. note::
-
- TODO: finish this section with APis for set_hostname, _read_hostname, update_hostname
-
-
-Users module
-------------
-
-The base class for this namespace can look like this
-
-
- class UserBase(ABCMeta):
-
- def groups(self):
- """Get all the user groups from the instance.
-
- Similar with network.routes() et al, that is
-
- >>> groups = distro.users.groups()
- sequence(Group(...), Group(....), ...)
- # create a new group
- >>> group = distro.users.Group.create(name)
- # Add new members to a group
- >>> group.add(member)
- # Remove a group
- >>> group.delete()
- # Iterate groups
- >>> list(groups)
-
- This gets rid of ``cloudinit.distros.Distro.create_group``,
- which creates a group and adds members to it as well and it get rids of
- ``cloudbaseinit.osutils.add_user_to_local``.
- """
-
- def users(self):
- """Get all the users from the instance.
-
- Using the same idion as for :meth:`routes` and :meth:`groups`.
-
- >>> users = distro.users.users()
- # containment (cloudbaseinit.osutils.user_exists)
- >>> user in users
- # Iteration
- >>> for i in user: print(user)
- """
-
- class User:
- """ Abstracts away user interaction.
-
- # Creating a new user.
- >>> User.create(username=..., password=..., ...)
- # get the home dir of an user
- >>> user.home()
- # Get the password (?)
- >>> user.password
- # Set the password
- >>> user.password = ....
- # Get an instance of an User from a name
- >>> user = distros.users.User.from_name('user')
- # Disable login password
- >>> user.disable_login_password()
- # Get ssh keys
- >>> keys = user.ssh_keys()
-
- Posix specific implementations might provide some method
- to operate with '/etc/sudoers' file.
- """
-
-.. note::
-
- TODO: what is cloudinit.distros.get_default_user?
-
-Packaging module
-----------------
-
-This object is a thin layer over Distro specific packaging utilities,
-used in cloudinit through ``distro.Distro.package_command``.
-Instead of passing strings with arguments, as it currently does,
-we could have a more OO approach:
-
- >>> distro.packaging.install(...)
-
- # cloudinit provides a ``package_command`` and an ``update_package_sources`` method,
- # which is:
- # self._runner.run("update-sources", self.package_command,
- # ["update"], freq=PER_INSTANCE)
- # distro.packaging.update() can be a noop operation if it was already called
- >>> distro.packaging.update(...)
-
- On Windows side, this can be implemented with OneGet.
-
-
-Filesystem module
------------------
-
-Layer over filesystem interaction specific for each OS.
-Most of the uses encountered are related to the concept of devices and partitions.
-
-
-class FilesystemBase(ABC):
-
- def devices(self):
- """Get a list of devices for this instance.
-
- As usual, this is abstracted through a container
- DevicesContainer([Device(...), Device(...), Device(...)])
-
- Where the container has the following API:
-
- >>> devices = distro.filesystem.devices()
- >>> devices.name, devices.type, devices.label
- >>> devices.size()
- # TODO: geometry on Windows? Define the concept better.
- >>> devices.layout()
- >>> device in devices
- >>> for device in devices: print(device)
- >>> devices.partitions()
- [DevicePartition('sda1'), DevicePartition('sda2'), ...]
- # TODO: FreeBSD has slices, which translates to partitions on
- # Windows and partitions of slices, how
- # does this translate with the current arch?
-
-
- Each DevicePartition shares a couple of methods / attributes with the Device,
- such as ``name``, ``type``, ``label``, ``size``. They have extra methods:
-
- >>> partition.resize()
- >>> partition.recover()
- >>> partition.mount()
- >>> with partition.mount(): # This can be noop on Windows.
- ....
-
- Obtaining either a device or a partition from a string, should be done
- in the following way:
-
- >>> device = Device.from_name('sda')
- >>> partition = DevicePartition.from_name('sda', 1)
- >>> partition = DevicePartition.from_name('sda1')
- """
-
-General module
---------------
-
-Here we could have other general OS utilities: terminate, apply_locale,
-set_timezone, execute_process etc. If some utilities can be grouped
-after some time into a more specialized namespace, then they can be moved.
-
-
-Drawbacks
-=========
-
-The only reasonable drawbacks that this proposal can have are:
-
- * moving all the parts from both projects will take a while.
- Since we started from the beginning knowing that cloudinit
- and cloudbaseinit codebases aren't compatible enough for a
- clean merge, this drawback might not be that huge. It's a pain
- that we must deal with as soon as possible.
-
- * the new API could be a source of unexpected bugs, but we should
- target a high testing coverage in order to alleviate this.
-
-
-
- .. _platform.system: https://docs.python.org/2/library/platform.html#platform.system
- .. _platform.linux_distribution: https://docs.python.org/2/library/platform.html#platform.linux_distribution
diff --git a/test-requirements.txt b/test-requirements.txt
deleted file mode 100644
index a27acde2..00000000
--- a/test-requirements.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-# The order of packages is significant, because pip processes them in the order
-# of appearance. Changing the order has an impact on the overall integration
-# process, which may cause wedges in the gate later.
-
-httpretty>=0.7.1,!=0.8.11,!=0.8.12
-mock
-nose
-testtools
-fixtures
-
-# For doc building
-sphinx>=1.2.0,<1.3
-oslosphinx
-
-# For style checking
-hacking<0.11,>=0.10.0
-doc8
-coverage
diff --git a/tools/noproxy b/tools/noproxy
deleted file mode 100644
index d371e63c..00000000
--- a/tools/noproxy
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env python
-#
-# clean http_proxy variables from environment as they make httpretty
-# fail, but may be in the environment for reasons such as pip install
-import os
-import sys
-
-for k in ('http_proxy', 'https_proxy', 'HTTP_PROXY', 'HTTPS_PROXY'):
- if k in os.environ:
- del os.environ[k]
-
-os.execvpe(sys.argv[1], sys.argv[1:], os.environ)
diff --git a/tools/tox-venv b/tools/tox-venv
deleted file mode 100755
index 32a16851..00000000
--- a/tools/tox-venv
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/bin/sh
-# vi: ts=4 expandtab
-
-error() { echo "$@" 1>&2; }
-fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
-list_environments() {
- local tox_d="$1" tox_ini="$2" prefix=" "
- envs=$(tox -c "$tox_ini" --listenvs) || return 1
- (
- cd "$tox_d" &&
- for d in ${envs}; do
- [ -f "$d/bin/activate" ] && s="*" || s=""
- echo "${prefix}$d$s";
- done
- )
-}
-
-Usage() {
- local tox_d="$1" tox_ini="$2"
- cat <&2; exit 1; }
-[ "$1" = "-h" -o "$1" = "--help" ] && { Usage "$tox_d" "$tox_ini"; exit 0; }
-
-[ -d "$tox_d" ] || fail "$tox_d: not a dir. maybe run 'tox'?"
-[ -f "$tox_ini" ] || fail "$tox_ini: did not find tox.ini"
-
-if [ "$1" = "-l" -o "$1" = "--list" ]; then
- list_environments "$tox_d" "$tox_ini"
- exit
-fi
-
-nocreate="false"
-if [ "$1" = "--no-create" ]; then
- nocreate="true"
- shift
-fi
-
-env="$1"
-shift
-activate="$tox_d/$env/bin/activate"
-
-if [ ! -f "$activate" ]; then
- if $nocreate; then
- fail "tox env '$env' did not exist, and no-create specified"
- elif list_environments "$tox_d" "$tox_ini" | grep -q " $env$"; then
- error "attempting to create $env:"
- error " tox -c $tox_ini --recreate --notest -e $env"
- tox -c "$tox_ini" --recreate --notest -e "$env" ||
- fail "failed creation of env $env"
- else
- error "$env: not a valid tox environment?"
- error "found tox_d=$tox_d"
- error "try one of:"
- list_environments "$tox_d" "$tox_ini" 1>&2
- fail
- fi
-fi
-. "$activate"
-
-[ "$#" -gt 0 ] || set -- ${SHELL:-/bin/bash}
-debian_chroot="tox:$env" exec "$@"
diff --git a/tox.ini b/tox.ini
deleted file mode 100644
index 88a25889..00000000
--- a/tox.ini
+++ /dev/null
@@ -1,48 +0,0 @@
-[tox]
-minversion = 1.6
-skipsdist = True
-envlist = py34, py27, docs, pep8, py34-coverage, py27-coverage
-
-[testenv]
-usedevelop = True
-# LC_ALL see https://github.com/gabrielfalcao/HTTPretty/issues/223
-setenv = VIRTUAL_ENV={envdir}
- LC_ALL = en_US.utf-8
-deps = -r{toxinidir}/test-requirements.txt
- -r{toxinidir}/requirements.txt
-commands = {envpython} {toxinidir}/tools/noproxy nosetests {posargs}
-
-# tox uses '--pre' by default to pip install. We don't want that, and
-# 'pip_pre=False' isn't available until tox version 1.9.
-install_command = pip install {opts} {packages}
-
-[testenv:py26]
-deps = {[testenv]deps}
- importlib
- logutils
-
-[testenv:py27-coverage]
-commands = {envpython} {toxinidir}/tools/noproxy nosetests --with-coverage --cover-erase --cover-package=cloudinit --cover-min-percentage=90 --cover-html {posargs}
-
-[testenv:py34-coverage]
-commands = {envpython} {toxinidir}/tools/noproxy nosetests --with-coverage --cover-erase --cover-package=cloudinit --cover-min-percentage=90 --cover-html {posargs}
-
-[testenv:pep8]
-commands = flake8 {posargs}
-
-[testenv:docs]
-whitelist_externals = git
-commands =
- git clean -fx doc/source/api
- python setup.py build_sphinx
- doc8 doc/source
-
-[testenv:venv]
-commands = {posargs}
-
-[flake8]
-builtins = _
-exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,.ropeproject
-
-# TODO(harlowja): fix these up...
-ignore = H102,H104,H105