diff options
author | Scott Moser <smoser@brickies.net> | 2017-01-20 10:06:55 -0500 |
---|---|---|
committer | Scott Moser <smoser@brickies.net> | 2017-01-20 10:06:55 -0500 |
commit | d00b7dba8767618ae360f56bf64b7ab7a8c49d2e (patch) | |
tree | 349799f76c39669a03a6acbd48502970c0abb994 | |
parent | fa3009b64949fef3744ddb940f01477dfa2d25e5 (diff) | |
parent | 7fb6f78177b5ece10ca7c54ba3958010a9987f06 (diff) | |
download | vyos-cloud-init-d00b7dba8767618ae360f56bf64b7ab7a8c49d2e.tar.gz vyos-cloud-init-d00b7dba8767618ae360f56bf64b7ab7a8c49d2e.zip |
merge from 0.7.9 at 0.7.9
421 files changed, 8798 insertions, 3744 deletions
@@ -1,3 +1,100 @@ +0.7.9: + - doc: adjust headers in tests documentation for consistency. + - pep8: fix issue found in zesty build with pycodestyle. + - integration test: initial commit of integration test framework + [Wesley Wiedenmeier] + - LICENSE: Allow dual licensing GPL-3 or Apache 2.0 [Jon Grimm] + - Fix config order of precedence, putting kernel command line over system. + [Wesley Wiedenmeier] (LP: #1582323) + - pep8: whitespace fix + - Update the list of valid ssh keys. [Michael Felt] + - network: add ENI unit test for statically rendered routes. + - set_hostname: avoid erroneously appending domain to fqdn + [Lars Kellogg-Stedman] (LP: #1647910) + - doc: change 'nobootwait' to 'nofail' in docs [Anhad Jai Singh] + - Replace an expired bit.ly link in code comment. + - user-groups: fix bug when groups was provided as string and had spaces + (LP: #1354694) + - mounts: use mount -a again to accomplish mounts (LP: #1647708) + - CloudSigma: Fix bug where datasource was not loaded in local search. + (LP: #1648380) + - when adding a user, strip whitespace from group list [Lars Kellogg-Stedman] + (LP: #1354694) + - fix decoding of utf-8 chars in yaml test + - Replace usage of sys_netdev_info with read_sys_net (LP: #1625766) + - fix problems found in python2.6 test. + - OpenStack: extend physical types to include hyperv, hw_veb, vhost_user. + (LP: #1642679) + - tests: fix assumptions that expected no eth0 in system. (LP: #1644043) + - net/cmdline: Consider ip= or ip6= on command line not only ip= + (LP: #1639930) + - Just use file logging by default (LP: #1643990) + - Improve formatting for ProcessExecutionError [Wesley Wiedenmeier] + - flake8: fix trailing white space + - Doc: various documentation fixes [Sean Bright] + - cloudinit/config/cc_rh_subscription.py: Remove repos before adding + [Brent Baude] + - packages/redhat: fix rpm spec file. + - main: set TZ in environment if not already set. [Ryan Harper] + - Azure: No longer rely on walinux agent. (LP: #1538522) + - disk_setup: Use sectors as unit when formatting MBR disks with sfdisk. + [Daniel Watkins] (LP: #1460715) + - Add activate_datasource, for datasource specific code paths. (LP: #1611074) + - systemd: cloud-init-local use RequiresMountsFor=/var/lib/cloud + (LP: #1642062) + - systemd: cloud-init remove After=systemd-networkd-wait-online + - systemd: cloud-init-local change Before basic to sysinit + - pep8: fix style errors reported by pycodestyle 2.1.0 + - systemd: drop both Wants and After local-fs.target + - systemd: networking service adjustments. (LP: #1636912) + - systemd: replace Before=basic.target, dbus.target with sysinit.target + (LP: #1629797) + - doc: Add documentation on stages of boot. + - doc: make the RST files consistently formated and other improvements. + - Ec2: fix syntax and tox in previous commit. + - Ec2: protect against non-dictionary in block-device-mapping. + - doc: fixed example to not overwrite /etc/hosts [Chris Glass] + - Doc: fix spelling / typos in ca_certs and scripts_vendor. + - pyflakes: fix issue with pyflakes 1.3 found in ubuntu zesty-proposed. + - net/cmdline: Further adjustments to ipv6 support [LaMont Jones] + (LP: #1621615) + - Add coverage dependency to bddeb to fix package build. + - doc: improve HACKING.rst file + - dmidecode: Allow dmidecode to be used on aarch64 [Robert Schweikert] + - AliYun: Add new datasource for Ali-Cloud ECS [kaihuan.pkh] + - Add coverage collection to tox unit tests. [Joshua Powers] + - cc_users_groups: fix remaing call to ds.normalize_user_groups [Ryan Harper] + - disk-config: udev settle after partitioning in gpt format. (LP: #1626243) + - unittests: do not read system /etc/cloud/cloud.cfg.d (LP: #1635350) + - Add documentation for logging features. [Wesley Wiedenmeier] + - Add support for snap create-user on Ubuntu Core images. [Ryan Harper] + - Fix sshd restarts for rhel distros. [Jim Gorz] + - OpenNebula: replace 'ip' parsing with cloudinit.net usage. + - Fix python2.6 things found running in centos 6. + - Move user/group functions to new ug_util file + - DigitalOcean: enable usage of data source by default. + - update Gentoo initscripts to run in the correct order [Matthew Thode] + - MAAS: improve the main of datasource to look at kernel cmdline config. + - tests: silence the Cheetah UserWarning about NameMapper C version. + - systemd: Run cloud-init.service Before dbus.socket not dbus.target + [Daniel Watkins] (LP: #1629797) + - systemd: run cloud-init.service Before dbus.service (LP: #1629797) + - unittests: fix use of mock 2.0 'assert_called' when running make check + [Ryan Harper] + - Improve module documentation and doc cleanup. [Wesley Wiedenmeier] + - lxd: Update network config for LXD 2.3 [Stéphane Graber] + - DigitalOcean: use meta-data for network configruation [Ben Howard] + - ntp: move to run after apt configuration (LP: #1628337) + - Decode unicode types in decode_binary [Robert Schweikert] + - systemd: Ensure that cloud-init-local happens before NetworkManager + - Allow ephemeral drive to be unpartitioned [Paul Meyer] + - subp: add 'update_env' argument + - net: support reading ipv6 dhcp config from initramfs [LaMont Jones] + (LP: #1621615, #1621507) + - Adjust mounts and disk configuration for systemd. (LP: #1611074) + - dmidecode: run dmidecode only on i?86 or x86_64 arch. [Robert Schweikert] + - systemd: put cloud-init.target After multi-user.target (LP: #1623868) + 0.7.8: - SmartOS: more improvements for network configuration - add ntp config module [Ryan Harper] @@ -1,674 +1,22 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - 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. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - 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 <http://www.gnu.org/licenses/>. - -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: - - <program> Copyright (C) <year> <name of author> - 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 -<http://www.gnu.org/licenses/>. - - 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 -<http://www.gnu.org/philosophy/why-not-lgpl.html>. +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 <http://www.gnu.org/licenses/> + +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 new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/LICENSE-Apache2.0 @@ -0,0 +1,202 @@ + + 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 new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/LICENSE-GPLv3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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 <http://www.gnu.org/licenses/>. + +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: + + <program> Copyright (C) <year> <name of author> + 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 +<http://www.gnu.org/licenses/>. + + 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 +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/cloudinit/__init__.py b/cloudinit/__init__.py index da124641..e69de29b 100644 --- a/cloudinit/__init__.py +++ b/cloudinit/__init__.py @@ -1,21 +0,0 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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 <http://www.gnu.org/licenses/>. diff --git a/cloudinit/atomic_helper.py b/cloudinit/atomic_helper.py index a3cfd942..fb2df8d5 100644 --- a/cloudinit/atomic_helper.py +++ b/cloudinit/atomic_helper.py @@ -1,5 +1,4 @@ -#!/usr/bin/python -# vi: ts=4 expandtab +# This file is part of cloud-init. See LICENSE file for license information. import json import os @@ -29,3 +28,5 @@ def write_json(filename, data, mode=_DEF_PERMS): return write_file( filename, json.dumps(data, indent=1, sort_keys=True) + "\n", omode="w", mode=mode) + +# vi: ts=4 expandtab diff --git a/cloudinit/cloud.py b/cloudinit/cloud.py index 3e6be203..b93a42ea 100644 --- a/cloudinit/cloud.py +++ b/cloudinit/cloud.py @@ -1,24 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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. +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import copy import os @@ -107,3 +91,5 @@ class Cloud(object): def get_ipath(self, name=None): return self.paths.get_ipath(name) + +# vi: ts=4 expandtab diff --git a/cloudinit/cmd/__init__.py b/cloudinit/cmd/__init__.py index da124641..e69de29b 100644 --- a/cloudinit/cmd/__init__.py +++ b/cloudinit/cmd/__init__.py @@ -1,21 +0,0 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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 <http://www.gnu.org/licenses/>. diff --git a/cloudinit/cmd/main.py b/cloudinit/cmd/main.py index fe37075e..c83496c5 100644 --- a/cloudinit/cmd/main.py +++ b/cloudinit/cmd/main.py @@ -1,25 +1,14 @@ #!/usr/bin/python -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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. +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import argparse import json @@ -694,4 +683,8 @@ def main(sysv_args=None): if __name__ == '__main__': + if 'TZ' not in os.environ: + os.environ['TZ'] = ":/etc/localtime" main(sys.argv) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/__init__.py b/cloudinit/config/__init__.py index d57453be..57e2a44d 100644 --- a/cloudinit/config/__init__.py +++ b/cloudinit/config/__init__.py @@ -1,23 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2008-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Chuck Short <chuck.short@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# -# 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. +# Copyright (C) 2008-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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 <http://www.gnu.org/licenses/>. +# Author: Chuck Short <chuck.short@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit.settings import (PER_INSTANCE, FREQUENCIES) @@ -56,3 +43,5 @@ def fixup_module(mod, def_freq=PER_INSTANCE): if not hasattr(mod, 'osfamilies'): setattr(mod, 'osfamilies', []) return mod + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_apt_configure.py b/cloudinit/config/cc_apt_configure.py index 6145fcd2..7f09c919 100644 --- a/cloudinit/config/cc_apt_configure.py +++ b/cloudinit/config/cc_apt_configure.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Apt Configure @@ -199,6 +187,8 @@ The ``source`` key supports variable replacements for the following strings: deb-src $MIRROR $RELEASE main restricted deb $PRIMARY $RELEASE universe restricted deb $SECURITY $RELEASE-security multiverse + debconf_selections: + set1: the-package the-package/some-flag boolean true conf: | APT { Get { @@ -216,9 +206,9 @@ The ``source`` key supports variable replacements for the following strings: keyserver: "keyserverurl" source: "deb http://<url>/ xenial main" source2: - source "ppa:<ppa-name>" + source: "ppa:<ppa-name>" source3: - source "deb $MIRROR $RELEASE multiverse" + source: "deb $MIRROR $RELEASE multiverse" key: | ------BEGIN PGP PUBLIC KEY BLOCK------- <key data> @@ -928,4 +918,4 @@ CONFIG_CLEANERS = { 'cloud-init': clean_cloud_init, } -# vi: ts=4 expandtab syntax=python +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_apt_pipelining.py b/cloudinit/config/cc_apt_pipelining.py index ab9d0054..cdf28cd9 100644 --- a/cloudinit/config/cc_apt_pipelining.py +++ b/cloudinit/config/cc_apt_pipelining.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# -# Author: Ben Howard <ben.howard@canonical.com> +# Copyright (C) 2011 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. +# Author: Ben Howard <ben.howard@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Apt Pipelining @@ -80,3 +68,5 @@ def write_apt_snippet(setting, log, f_name): file_contents = APT_PIPE_TPL % (setting) util.write_file(f_name, file_contents) log.debug("Wrote %s with apt pipeline depth setting %s", f_name, setting) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_bootcmd.py b/cloudinit/config/cc_bootcmd.py index 22b23f28..604f93b0 100644 --- a/cloudinit/config/cc_bootcmd.py +++ b/cloudinit/config/cc_bootcmd.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2011 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2011 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Bootcmd @@ -43,7 +31,7 @@ specified either as lists or strings. For invocation details, see ``runcmd``. bootcmd: - echo 192.168.1.130 us.archive.ubuntu.com > /etc/hosts - - [ cloud-nit-per, once, mymkfs, mkfs, /dev/vdb ] + - [ cloud-init-per, once, mymkfs, mkfs, /dev/vdb ] """ import os @@ -80,3 +68,5 @@ def handle(name, cfg, cloud, log, _args): except Exception: util.logexc(log, "Failed to run bootcmd module %s", name) raise + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_byobu.py b/cloudinit/config/cc_byobu.py index 4a616e26..8570da15 100755 --- a/cloudinit/config/cc_byobu.py +++ b/cloudinit/config/cc_byobu.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Byobu @@ -106,3 +94,5 @@ def handle(name, cfg, cloud, log, args): cmd = ["/bin/sh", "-c", "%s %s %s" % ("X=0;", shcmd, "exit $X")] log.debug("Setting byobu to %s", value) util.subp(cmd, capture=False) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_ca_certs.py b/cloudinit/config/cc_ca_certs.py index df77ba62..64bc900e 100644 --- a/cloudinit/config/cc_ca_certs.py +++ b/cloudinit/config/cc_ca_certs.py @@ -1,18 +1,6 @@ -# vi: ts=4 expandtab -# -# Author: Mike Milner <mike.milner@canonical.com> -# -# 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. +# Author: Mike Milner <mike.milner@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ CA Certs @@ -134,3 +122,5 @@ def handle(name, cfg, _cloud, log, _args): # Update the system with the new cert configuration. log.debug("Updating certificates") update_ca_certs() + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_chef.py b/cloudinit/config/cc_chef.py index 922fb6af..f6564e5c 100644 --- a/cloudinit/config/cc_chef.py +++ b/cloudinit/config/cc_chef.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Avishai Ish-Shalom <avishai@fewbytes.com> -# Author: Mike Moulton <mike@meltmedia.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Avishai Ish-Shalom <avishai@fewbytes.com> +# Author: Mike Moulton <mike@meltmedia.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Chef @@ -348,3 +336,5 @@ def install_chef_from_gems(ruby_version, chef_version, distro): util.subp(['/usr/bin/gem', 'install', 'chef', '--no-ri', '--no-rdoc', '--bindir', '/usr/bin', '-q'], capture=False) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_debug.py b/cloudinit/config/cc_debug.py index 5ab36469..0a039eb3 100644 --- a/cloudinit/config/cc_debug.py +++ b/cloudinit/config/cc_debug.py @@ -1,18 +1,6 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2013 Yahoo! Inc. -# -# 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. +# Copyright (C) 2013 Yahoo! Inc. # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Debug @@ -113,3 +101,5 @@ def handle(name, cfg, cloud, log, args): util.write_file(out_file, "".join(content_to_file), 0o644, "w") else: util.multi_log("".join(content_to_file), console=True, stderr=False) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_disable_ec2_metadata.py b/cloudinit/config/cc_disable_ec2_metadata.py index 5c54e6f4..c56319b5 100644 --- a/cloudinit/config/cc_disable_ec2_metadata.py +++ b/cloudinit/config/cc_disable_ec2_metadata.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Disable EC2 Metadata @@ -54,3 +42,5 @@ def handle(name, cfg, _cloud, log, _args): else: log.debug(("Skipping module named %s," " disabling the ec2 route not enabled"), name) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_disk_setup.py b/cloudinit/config/cc_disk_setup.py index 0c4b794d..38df13ab 100644 --- a/cloudinit/config/cc_disk_setup.py +++ b/cloudinit/config/cc_disk_setup.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Ben Howard <ben.howard@canonical.com> -# -# 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. +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Ben Howard <ben.howard@canonical.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Disk Setup @@ -436,14 +424,13 @@ def get_dyn_func(*args): def get_mbr_hdd_size(device): - size_cmd = [SFDISK_CMD, '--show-size', device] - size = None try: - size, _err = util.subp(size_cmd) + size_in_bytes, _ = util.subp([BLKDEV_CMD, '--getsize64', device]) + sector_size, _ = util.subp([BLKDEV_CMD, '--getss', device]) except Exception as e: raise Exception("Failed to get %s size\n%s" % (device, e)) - return int(size.strip()) + return int(size_in_bytes) / int(sector_size) def get_gpt_hdd_size(device): @@ -588,7 +575,7 @@ def get_partition_mbr_layout(size, layout): raise Exception("Partition was incorrectly defined: %s" % part) percent, part_type = part - part_size = int((float(size) * (float(percent) / 100)) / 1024) + part_size = int(float(size) * (float(percent) / 100)) if part_num == last_part_num: part_definition.append(",,%s" % part_type) @@ -692,7 +679,7 @@ def exec_mkpart_mbr(device, layout): types, i.e. gpt """ # Create the partitions - prt_cmd = [SFDISK_CMD, "--Linux", "-uM", device] + prt_cmd = [SFDISK_CMD, "--Linux", "--unit=S", "--force", device] try: util.subp(prt_cmd, data="%s\n" % layout) except Exception as e: @@ -909,7 +896,8 @@ def mkfs(fs_cfg): LOG.debug("Error in device identification handling.") return - LOG.debug("File system %s will be created on %s", label, device) + LOG.debug("File system type '%s' with label '%s' will be created on %s", + fs_type, label, device) # Make sure the device is defined if not device: @@ -958,3 +946,5 @@ def mkfs(fs_cfg): util.subp(fs_cmd) except Exception as e: raise Exception("Failed to exec of '%s':\n%s" % (fs_cmd, e)) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_emit_upstart.py b/cloudinit/config/cc_emit_upstart.py index a7be6351..69dc2d5e 100644 --- a/cloudinit/config/cc_emit_upstart.py +++ b/cloudinit/config/cc_emit_upstart.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Emit Upstart @@ -82,3 +70,5 @@ def handle(name, _cfg, cloud, log, args): except Exception as e: # TODO(harlowja), use log exception from utils?? log.warn("Emission of upstart event %s failed due to: %s", n, e) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_fan.py b/cloudinit/config/cc_fan.py index 6027fdc7..f0cda3d5 100644 --- a/cloudinit/config/cc_fan.py +++ b/cloudinit/config/cc_fan.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Canonical Ltd. -# -# Author: Scott Moser <scott.moser@canonical.com> +# Copyright (C) 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. +# Author: Scott Moser <scott.moser@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Fan @@ -112,3 +100,5 @@ def handle(name, cfg, cloud, log, args): stop_update_start( service='ubuntu-fan', config_file=mycfg.get('config_path'), content=mycfg.get('config'), systemd=distro.uses_systemd()) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_final_message.py b/cloudinit/config/cc_final_message.py index 5e144fde..c61f03d4 100644 --- a/cloudinit/config/cc_final_message.py +++ b/cloudinit/config/cc_final_message.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Final Message @@ -96,3 +84,5 @@ def handle(_name, cfg, cloud, log, args): if cloud.datasource.is_disconnected: log.warn("Used fallback datasource") + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_foo.py b/cloudinit/config/cc_foo.py index ad0e0468..924b967c 100644 --- a/cloudinit/config/cc_foo.py +++ b/cloudinit/config/cc_foo.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Foo @@ -64,3 +52,5 @@ frequency = PER_INSTANCE def handle(name, _cfg, _cloud, log, _args): log.debug("Hi from module %s", name) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_growpart.py b/cloudinit/config/cc_growpart.py index 03df6047..832bb3fd 100644 --- a/cloudinit/config/cc_growpart.py +++ b/cloudinit/config/cc_growpart.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Growpart @@ -356,3 +344,5 @@ def handle(_name, cfg, _cloud, log, _args): RESIZERS = (('growpart', ResizeGrowPart), ('gpart', ResizeGpart)) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_grub_dpkg.py b/cloudinit/config/cc_grub_dpkg.py index 33ca40a1..a323edfa 100644 --- a/cloudinit/config/cc_grub_dpkg.py +++ b/cloudinit/config/cc_grub_dpkg.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Grub Dpkg @@ -105,3 +93,5 @@ def handle(name, cfg, _cloud, log, _args): util.subp(['debconf-set-selections'], dconf_sel) except Exception: util.logexc(log, "Failed to run debconf-set-selections for grub-dpkg") + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_keys_to_console.py b/cloudinit/config/cc_keys_to_console.py index d4b2013e..efedd4ae 100644 --- a/cloudinit/config/cc_keys_to_console.py +++ b/cloudinit/config/cc_keys_to_console.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Keys to Console @@ -84,3 +72,5 @@ def handle(name, cfg, cloud, log, _args): except Exception: log.warn("Writing keys to the system console failed!") raise + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_landscape.py b/cloudinit/config/cc_landscape.py index 11c84513..86b71383 100644 --- a/cloudinit/config/cc_landscape.py +++ b/cloudinit/config/cc_landscape.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Landscape @@ -146,3 +134,5 @@ def merge_together(objs): else: cfg.merge(ConfigObj(obj)) return cfg + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_locale.py b/cloudinit/config/cc_locale.py index 268888e2..f68c3cc7 100644 --- a/cloudinit/config/cc_locale.py +++ b/cloudinit/config/cc_locale.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Locale @@ -55,3 +43,5 @@ def handle(name, cfg, cloud, log, args): log.debug("Setting locale to %s", locale) locale_cfgfile = util.get_cfg_option_str(cfg, "locale_configfile") cloud.distro.apply_locale(locale, locale_cfgfile) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_lxd.py b/cloudinit/config/cc_lxd.py index 3e7faca7..e6262f8c 100644 --- a/cloudinit/config/cc_lxd.py +++ b/cloudinit/config/cc_lxd.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2016 Canonical Ltd. -# -# Author: Wesley Wiedenmeier <wesley.wiedenmeier@canonical.com> +# Copyright (C) 2016 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. +# Author: Wesley Wiedenmeier <wesley.wiedenmeier@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ LXD @@ -262,3 +250,5 @@ def bridge_to_cmd(bridge_cfg): cmd_create.append("--force-local") return cmd_create, cmd_attach + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_mcollective.py b/cloudinit/config/cc_mcollective.py index c447f266..d5f63f5f 100644 --- a/cloudinit/config/cc_mcollective.py +++ b/cloudinit/config/cc_mcollective.py @@ -1,23 +1,11 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Marc Cluet <marc.cluet@canonical.com> -# Based on code by Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Marc Cluet <marc.cluet@canonical.com> +# Based on code by Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Mcollective @@ -155,3 +143,5 @@ def handle(name, cfg, cloud, log, _args): # restart mcollective to handle updated config util.subp(['service', 'mcollective', 'restart'], capture=False) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_migrator.py b/cloudinit/config/cc_migrator.py index 6e0bf4bb..3995704a 100644 --- a/cloudinit/config/cc_migrator.py +++ b/cloudinit/config/cc_migrator.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Migrator @@ -105,3 +93,5 @@ def handle(name, cfg, cloud, log, _args): log.debug("Migrated %s semaphore files to there canonicalized names", sems_moved) _migrate_legacy_sems(cloud, log) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_mounts.py b/cloudinit/config/cc_mounts.py index 452c9e83..5b630f8b 100644 --- a/cloudinit/config/cc_mounts.py +++ b/cloudinit/config/cc_mounts.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# -# 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. +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Mounts @@ -42,6 +30,14 @@ values. It defaults to:: mount_default_fields: [none, none, "auto", "defaults,nobootwait", "0", "2"] +On a systemd booted system that default is the mostly equivalent:: + + mount_default_fields: [none, none, "auto", + "defaults,nofail,x-systemd.requires=cloud-init.service", "0", "2"] + +Note that `nobootwait` is an upstart specific boot option that somewhat +equates to the more standard `nofail`. + Swap files can be configured by setting the path to the swap file to create with ``filename``, the size of the swap file with ``size`` maximum size of the swap file if using an ``size: auto`` with ``maxsize``. By default no @@ -58,8 +54,8 @@ swap file is created. mounts: - [ /dev/ephemeral0, /mnt, auto, "defaults,noexec" ] - [ sdc, /opt/data ] - - [ xvdh, /opt/data, "auto", "defaults,nobootwait", "0", "0" ] - mount_default_fields: [None, None, "auto", "nefaults,nobootwait", "0", "2"] + - [ xvdh, /opt/data, "auto", "defaults,nofail", "0", "0" ] + mount_default_fields: [None, None, "auto", "defaults,nofail", "0", "2"] swap: filename: <file> size: <"auto"/size in bytes> @@ -327,6 +323,8 @@ def handle(_name, cfg, cloud, log, _args): if "mounts" in cfg: cfgmnt = cfg["mounts"] + LOG.debug("mounts configuration is %s", cfgmnt) + for i in range(len(cfgmnt)): # skip something that wasn't a list if not isinstance(cfgmnt[i], list): @@ -423,37 +421,53 @@ def handle(_name, cfg, cloud, log, _args): cc_lines.append('\t'.join(line)) fstab_lines = [] + removed = [] for line in util.load_file(FSTAB_PATH).splitlines(): try: toks = WS.split(line) if toks[3].find(comment) != -1: + removed.append(line) continue except Exception: pass fstab_lines.append(line) + for d in dirs: + try: + util.ensure_dir(d) + except Exception: + util.logexc(log, "Failed to make '%s' config-mount", d) + + sadds = [WS.sub(" ", n) for n in cc_lines] + sdrops = [WS.sub(" ", n) for n in removed] + + sops = (["- " + drop for drop in sdrops if drop not in sadds] + + ["+ " + add for add in sadds if add not in sdrops]) + fstab_lines.extend(cc_lines) contents = "%s\n" % ('\n'.join(fstab_lines)) util.write_file(FSTAB_PATH, contents) + activate_cmds = [] if needswap: - try: - util.subp(("swapon", "-a")) - except Exception: - util.logexc(log, "Activating swap via 'swapon -a' failed") + activate_cmds.append(["swapon", "-a"]) - for d in dirs: + if len(sops) == 0: + log.debug("No changes to /etc/fstab made.") + else: + log.debug("Changes to fstab: %s", sops) + activate_cmds.append(["mount", "-a"]) + if uses_systemd: + activate_cmds.append(["systemctl", "daemon-reload"]) + + fmt = "Activating swap and mounts with: %s" + for cmd in activate_cmds: + fmt = "Activate mounts: %s:" + ' '.join(cmd) try: - util.ensure_dir(d) - except Exception: - util.logexc(log, "Failed to make '%s' config-mount", d) + util.subp(cmd) + log.debug(fmt, "PASS") + except util.ProcessExecutionError: + log.warn(fmt, "FAIL") + util.logexc(log, fmt, "FAIL") - activate_cmd = ["mount", "-a"] - if uses_systemd: - activate_cmd = ["systemctl", "daemon-reload"] - fmt = "Activate mounts: %s:" + ' '.join(activate_cmd) - try: - util.subp(activate_cmd) - LOG.debug(fmt, "PASS") - except util.ProcessExecutionError: - util.logexc(log, fmt, "FAIL") +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_ntp.py b/cloudinit/config/cc_ntp.py index 7cda3172..e33032fd 100644 --- a/cloudinit/config/cc_ntp.py +++ b/cloudinit/config/cc_ntp.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2016 Canonical Ltd. -# -# Author: Ryan Harper <ryan.harper@canonical.com> +# Copyright (C) 2016 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. +# Author: Ryan Harper <ryan.harper@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ NTP @@ -136,3 +124,5 @@ def write_ntp_config_template(cfg, cloud): "not rendering %s"), NTP_CONF) templater.render_to_file(template_fn, NTP_CONF, params) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_package_update_upgrade_install.py b/cloudinit/config/cc_package_update_upgrade_install.py index 6d717616..17b91011 100644 --- a/cloudinit/config/cc_package_update_upgrade_install.py +++ b/cloudinit/config/cc_package_update_upgrade_install.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Package Update Upgrade Install @@ -132,3 +120,5 @@ def handle(_name, cfg, cloud, log, _args): log.warn("%s failed with exceptions, re-raising the last one", len(errors)) raise errors[-1] + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_phone_home.py b/cloudinit/config/cc_phone_home.py index cb70d39c..878069b7 100644 --- a/cloudinit/config/cc_phone_home.py +++ b/cloudinit/config/cc_phone_home.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Phone Home @@ -154,3 +142,5 @@ def handle(name, cfg, cloud, log, args): except Exception: util.logexc(log, "Failed to post phone home data to %s in %s tries", url, tries) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_power_state_change.py b/cloudinit/config/cc_power_state_change.py index 61b5416a..c1c6fe7e 100644 --- a/cloudinit/config/cc_power_state_change.py +++ b/cloudinit/config/cc_power_state_change.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# -# Author: Scott Moser <scott.moser@canonical.com> +# Copyright (C) 2011 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. +# Author: Scott Moser <scott.moser@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Power State Change @@ -266,3 +254,5 @@ def run_after_pid_gone(pid, pidcmdline, timeout, log, condition, func, args): fatal("Unexpected Exception when checking condition: %s" % e) func(*args) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_puppet.py b/cloudinit/config/cc_puppet.py index bfd630d2..dc11561b 100644 --- a/cloudinit/config/cc_puppet.py +++ b/cloudinit/config/cc_puppet.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Puppet @@ -161,3 +149,5 @@ def handle(name, cfg, cloud, log, _args): # Start puppetd util.subp(['service', 'puppet', 'start'], capture=False) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_resizefs.py b/cloudinit/config/cc_resizefs.py index f3c36c9b..e028abf4 100644 --- a/cloudinit/config/cc_resizefs.py +++ b/cloudinit/config/cc_resizefs.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Resizefs @@ -210,3 +198,5 @@ def do_resize(resize_cmd, log): raise # TODO(harlowja): Should we add a fsck check after this to make # sure we didn't corrupt anything? + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_resolv_conf.py b/cloudinit/config/cc_resolv_conf.py index feea5653..9c5cd1fe 100644 --- a/cloudinit/config/cc_resolv_conf.py +++ b/cloudinit/config/cc_resolv_conf.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2013 Craig Tracey -# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Craig Tracey <craigtracey@gmail.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2013 Craig Tracey +# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Craig Tracey <craigtracey@gmail.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Resolv Conf @@ -123,3 +111,5 @@ def handle(name, cfg, cloud, log, _args): generate_resolv_conf(template_fn=template_fn, params=cfg["resolv_conf"]) return + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_rh_subscription.py b/cloudinit/config/cc_rh_subscription.py index d858f65c..7f36cf8f 100644 --- a/cloudinit/config/cc_rh_subscription.py +++ b/cloudinit/config/cc_rh_subscription.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Red Hat, Inc. -# -# Author: Brent Baude <bbaude@redhat.com> +# Copyright (C) 2015 Red Hat, Inc. # -# 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. +# Author: Brent Baude <bbaude@redhat.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ RedHat Subscription @@ -421,11 +409,12 @@ class SubscriptionManager(object): "because it is not enabled".format(fail)) cmd = ['repos'] - if len(enable_list) > 0: - cmd.extend(enable_list) if len(disable_list) > 0: cmd.extend(disable_list) + if len(enable_list) > 0: + cmd.extend(enable_list) + try: self._sub_man_cli(cmd) except util.ProcessExecutionError as e: @@ -442,3 +431,5 @@ class SubscriptionManager(object): def is_configured(self): return bool((self.userid and self.password) or self.activation_key) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_rightscale_userdata.py b/cloudinit/config/cc_rightscale_userdata.py index 6cf8c948..4e34c7e9 100644 --- a/cloudinit/config/cc_rightscale_userdata.py +++ b/cloudinit/config/cc_rightscale_userdata.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Rightscale Userdata @@ -126,3 +114,5 @@ def handle(name, _cfg, cloud, log, _args): log.warn("%s failed with exceptions, re-raising the last one", len(captured_excps)) raise captured_excps[-1] + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_rsyslog.py b/cloudinit/config/cc_rsyslog.py index 1c12e567..50316214 100644 --- a/cloudinit/config/cc_rsyslog.py +++ b/cloudinit/config/cc_rsyslog.py @@ -1,22 +1,11 @@ -# vi: ts=4 expandtab syntax=python -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# -# 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. +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. + """ .. _cc_rsyslog: @@ -451,3 +440,5 @@ def handle(name, cfg, cloud, log, _args): # This should now use rsyslog if # the logging was setup to use it... log.debug("%s configured %s files", name, changes) + +# vi: ts=4 expandtab syntax=python diff --git a/cloudinit/config/cc_runcmd.py b/cloudinit/config/cc_runcmd.py index 23e1e898..dfa8cb3d 100644 --- a/cloudinit/config/cc_runcmd.py +++ b/cloudinit/config/cc_runcmd.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Runcmd @@ -68,3 +56,5 @@ def handle(name, cfg, cloud, log, _args): util.write_file(out_fn, content, 0o700) except Exception: util.logexc(log, "Failed to shellify %s into file %s", cmd, out_fn) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_salt_minion.py b/cloudinit/config/cc_salt_minion.py index 90786658..2b388372 100644 --- a/cloudinit/config/cc_salt_minion.py +++ b/cloudinit/config/cc_salt_minion.py @@ -1,18 +1,6 @@ -# vi: ts=4 expandtab -# -# Author: Jeff Bauer <jbauer@rubic.com> -# -# 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. +# Author: Jeff Bauer <jbauer@rubic.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Salt Minion @@ -95,3 +83,5 @@ def handle(name, cfg, cloud, log, _args): # restart salt-minion. 'service' will start even if not started. if it # was started, it needs to be restarted for config change. util.subp(['service', 'salt-minion', 'restart'], capture=False) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_scripts_per_boot.py b/cloudinit/config/cc_scripts_per_boot.py index 0736cf7e..b03255c7 100644 --- a/cloudinit/config/cc_scripts_per_boot.py +++ b/cloudinit/config/cc_scripts_per_boot.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Scripts Per Boot @@ -55,3 +43,5 @@ def handle(name, _cfg, cloud, log, _args): log.warn("Failed to run module %s (%s in %s)", name, SCRIPT_SUBDIR, runparts_path) raise + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_scripts_per_instance.py b/cloudinit/config/cc_scripts_per_instance.py index c71d154b..baee5cc4 100644 --- a/cloudinit/config/cc_scripts_per_instance.py +++ b/cloudinit/config/cc_scripts_per_instance.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Scripts Per Instance @@ -55,3 +43,5 @@ def handle(name, _cfg, cloud, log, _args): log.warn("Failed to run module %s (%s in %s)", name, SCRIPT_SUBDIR, runparts_path) raise + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_scripts_per_once.py b/cloudinit/config/cc_scripts_per_once.py index bf637eea..4943e9aa 100644 --- a/cloudinit/config/cc_scripts_per_once.py +++ b/cloudinit/config/cc_scripts_per_once.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Scripts Per Once @@ -55,3 +43,5 @@ def handle(name, _cfg, cloud, log, _args): log.warn("Failed to run module %s (%s in %s)", name, SCRIPT_SUBDIR, runparts_path) raise + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_scripts_user.py b/cloudinit/config/cc_scripts_user.py index 54338a43..6c66481e 100644 --- a/cloudinit/config/cc_scripts_user.py +++ b/cloudinit/config/cc_scripts_user.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Scripts User @@ -59,3 +47,5 @@ def handle(name, _cfg, cloud, log, _args): log.warn("Failed to run module %s (%s in %s)", name, SCRIPT_SUBDIR, runparts_path) raise + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_scripts_vendor.py b/cloudinit/config/cc_scripts_vendor.py index f6d38c36..0292eafb 100644 --- a/cloudinit/config/cc_scripts_vendor.py +++ b/cloudinit/config/cc_scripts_vendor.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2014 Canonical Ltd. -# -# Author: Ben Howard <ben.howard@canonical.com> +# Copyright (C) 2014 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. +# Author: Ben Howard <ben.howard@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Scripts Vendor @@ -63,3 +51,5 @@ def handle(name, cfg, cloud, log, _args): log.warn("Failed to run module %s (%s in %s)", name, SCRIPT_SUBDIR, runparts_path) raise + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_seed_random.py b/cloudinit/config/cc_seed_random.py index d84255ed..e76b9c09 100644 --- a/cloudinit/config/cc_seed_random.py +++ b/cloudinit/config/cc_seed_random.py @@ -1,23 +1,11 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2013 Yahoo! Inc. -# Copyright (C) 2014 Canonical, Ltd -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# Author: Dustin Kirkland <kirkland@ubuntu.com> -# Author: Scott Moser <scott.moser@canonical.com> +# Copyright (C) 2013 Yahoo! Inc. +# Copyright (C) 2014 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Author: Dustin Kirkland <kirkland@ubuntu.com> +# Author: Scott Moser <scott.moser@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Seed Random @@ -144,3 +132,5 @@ def handle(name, cfg, cloud, log, _args): except ValueError as e: log.warn("handling random command [%s] failed: %s", command, e) raise e + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_set_hostname.py b/cloudinit/config/cc_set_hostname.py index c35cefee..e42799f9 100644 --- a/cloudinit/config/cc_set_hostname.py +++ b/cloudinit/config/cc_set_hostname.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Set Hostname @@ -61,3 +49,5 @@ def handle(name, cfg, cloud, log, _args): util.logexc(log, "Failed to set the hostname to %s (%s)", fqdn, hostname) raise + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_set_passwords.py b/cloudinit/config/cc_set_passwords.py index 6fc00517..cf1f59ec 100755 --- a/cloudinit/config/cc_set_passwords.py +++ b/cloudinit/config/cc_set_passwords.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Set Passwords @@ -207,3 +195,5 @@ def handle(_name, cfg, cloud, log, args): def rand_user_password(pwlen=9): return util.rand_str(pwlen, select_from=PW_SET) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_snap_config.py b/cloudinit/config/cc_snap_config.py index 275a2d09..db511661 100644 --- a/cloudinit/config/cc_snap_config.py +++ b/cloudinit/config/cc_snap_config.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2016 Canonical Ltd. -# -# Author: Ryan Harper <ryan.harper@canonical.com> +# Copyright (C) 2016 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. +# Author: Ryan Harper <ryan.harper@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Snappy @@ -182,3 +170,5 @@ def handle(name, cfg, cloud, log, args): usercfg = add_snap_user(cfg=cfgin) if usercfg: cloud.distro.create_user(usercfg.get('snapuser'), **usercfg) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_snappy.py b/cloudinit/config/cc_snappy.py index e03ec483..6ea81b84 100644 --- a/cloudinit/config/cc_snappy.py +++ b/cloudinit/config/cc_snappy.py @@ -1,16 +1,4 @@ -# vi: ts=4 expandtab -# -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Snappy @@ -321,3 +309,5 @@ def handle(name, cfg, cloud, log, args): if fails: raise Exception("failed to install/configure snaps") + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_spacewalk.py b/cloudinit/config/cc_spacewalk.py index 99b63a84..1020e944 100644 --- a/cloudinit/config/cc_spacewalk.py +++ b/cloudinit/config/cc_spacewalk.py @@ -1,16 +1,4 @@ -# vi: ts=4 expandtab -# -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Spacewalk @@ -98,3 +86,5 @@ def handle(name, cfg, cloud, log, _args): else: log.debug("Skipping module named %s, 'spacewalk/server' key" " was not found in configuration", name) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_ssh.py b/cloudinit/config/cc_ssh.py index 576fa58a..45204a07 100755 --- a/cloudinit/config/cc_ssh.py +++ b/cloudinit/config/cc_ssh.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ SSH @@ -223,3 +211,5 @@ def apply_credentials(keys, user, disable_root, disable_root_opts): key_prefix = '' ssh_util.setup_user_keys(keys, 'root', options=key_prefix) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_ssh_authkey_fingerprints.py b/cloudinit/config/cc_ssh_authkey_fingerprints.py index 7eeb0f84..0066e97f 100755 --- a/cloudinit/config/cc_ssh_authkey_fingerprints.py +++ b/cloudinit/config/cc_ssh_authkey_fingerprints.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ SSH Authkey Fingerprints @@ -120,3 +108,5 @@ def handle(name, cfg, cloud, log, _args): (key_fn, key_entries) = ssh_util.extract_authorized_keys(user_name) _pprint_key_entries(user_name, key_fn, key_entries, hash_meth) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_ssh_import_id.py b/cloudinit/config/cc_ssh_import_id.py index 1be96dc5..6b46dafe 100755 --- a/cloudinit/config/cc_ssh_import_id.py +++ b/cloudinit/config/cc_ssh_import_id.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ SSH Import Id @@ -117,3 +105,5 @@ def import_ssh_ids(ids, user, log): except util.ProcessExecutionError as exc: util.logexc(log, "Failed to run command to import %s ssh ids", user) raise exc + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_timezone.py b/cloudinit/config/cc_timezone.py index 7024b07b..a9de8fac 100644 --- a/cloudinit/config/cc_timezone.py +++ b/cloudinit/config/cc_timezone.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Timezone @@ -57,3 +45,5 @@ def handle(name, cfg, cloud, log, args): # Let the distro handle settings its timezone cloud.distro.set_timezone(timezone) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_ubuntu_init_switch.py b/cloudinit/config/cc_ubuntu_init_switch.py index 31a96e4a..5dd26901 100644 --- a/cloudinit/config/cc_ubuntu_init_switch.py +++ b/cloudinit/config/cc_ubuntu_init_switch.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2014 Canonical Ltd. -# -# Author: Scott Moser <scott.moser@canonical.com> +# Copyright (C) 2014 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. +# Author: Scott Moser <scott.moser@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Ubuntu Init Switch @@ -168,3 +156,5 @@ def _fire_reboot(log, wait_attempts=6, initial_sleep=1, backoff=2): elapsed = time.time() - start raise RuntimeError(("Reboot did not happen" " after %s seconds!") % (int(elapsed))) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_update_etc_hosts.py b/cloudinit/config/cc_update_etc_hosts.py index 3fcb2652..b3947849 100644 --- a/cloudinit/config/cc_update_etc_hosts.py +++ b/cloudinit/config/cc_update_etc_hosts.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Update Etc Hosts @@ -101,3 +89,5 @@ def handle(name, cfg, cloud, log, _args): else: log.debug(("Configuration option 'manage_etc_hosts' is not set," " not managing /etc/hosts in module %s"), name) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_update_hostname.py b/cloudinit/config/cc_update_hostname.py index 315b7b6f..d5f4eb5a 100644 --- a/cloudinit/config/cc_update_hostname.py +++ b/cloudinit/config/cc_update_hostname.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Update Hostname @@ -66,3 +54,5 @@ def handle(name, cfg, cloud, log, _args): util.logexc(log, "Failed to update the hostname to %s (%s)", fqdn, hostname) raise + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_users_groups.py b/cloudinit/config/cc_users_groups.py index 36352362..59649800 100644 --- a/cloudinit/config/cc_users_groups.py +++ b/cloudinit/config/cc_users_groups.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# -# Author: Ben Howard <ben.howard@canonical.com> +# Copyright (C) 2012 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. +# Author: Ben Howard <ben.howard@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Users and Groups @@ -112,3 +100,5 @@ def handle(name, cfg, cloud, _log, _args): cloud.distro.create_group(name, members) for (user, config) in users.items(): cloud.distro.create_user(user, **config) + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_write_files.py b/cloudinit/config/cc_write_files.py index b5956bda..72e1cdd6 100644 --- a/cloudinit/config/cc_write_files.py +++ b/cloudinit/config/cc_write_files.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Write Files @@ -145,3 +133,5 @@ def extract_contents(contents, extraction_types): elif t == UNKNOWN_ENC: pass return result + +# vi: ts=4 expandtab diff --git a/cloudinit/config/cc_yum_add_repo.py b/cloudinit/config/cc_yum_add_repo.py index eb94c1f3..ef8535ed 100644 --- a/cloudinit/config/cc_yum_add_repo.py +++ b/cloudinit/config/cc_yum_add_repo.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. """ Yum Add Repo @@ -133,3 +121,5 @@ def handle(name, cfg, _cloud, log, _args): repo_blob = _format_repository_config(c_repo_id, repo_configs.get(c_repo_id)) util.write_file(path, repo_blob) + +# vi: ts=4 expandtab diff --git a/cloudinit/cs_utils.py b/cloudinit/cs_utils.py index 412431f2..51c09582 100644 --- a/cloudinit/cs_utils.py +++ b/cloudinit/cs_utils.py @@ -1,20 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2014 CloudSigma -# -# Author: Kiril Vladimiroff <kiril.vladimiroff@cloudsigma.com> -# -# 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. +# Copyright (C) 2014 CloudSigma # -# 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. +# Author: Kiril Vladimiroff <kiril.vladimiroff@cloudsigma.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. + """ cepko implements easy-to-use communication with CloudSigma's VMs through a virtual serial port without bothering with formatting the messages @@ -104,3 +93,5 @@ class CepkoResult(object): def __iter__(self): return self.result.__iter__() + +# vi: ts=4 expandtab diff --git a/cloudinit/dhclient_hook.py b/cloudinit/dhclient_hook.py index 82cb1855..7f02d7fa 100644 --- a/cloudinit/dhclient_hook.py +++ b/cloudinit/dhclient_hook.py @@ -1,5 +1,4 @@ -#!/usr/bin/python -# vi: ts=4 expandtab +# This file is part of cloud-init. See LICENSE file for license information. import os @@ -48,3 +47,5 @@ class LogDhclient(object): return atomic_helper.write_json(self.hook_file, self.get_vals(envs)) LOG.debug("Wrote dhclient options in %s", self.hook_file) + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py index 4a726430..f3d395b9 100755 --- a/cloudinit/distros/__init__.py +++ b/cloudinit/distros/__init__.py @@ -1,25 +1,13 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# Author: Ben Howard <ben.howard@canonical.com> -# -# 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. +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Author: Ben Howard <ben.howard@canonical.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import six from six import StringIO @@ -398,13 +386,17 @@ class Distro(object): # support kwargs having groups=[list] or groups="g1,g2" groups = kwargs.get('groups') if groups: - if isinstance(groups, (list, tuple)): - # kwargs.items loop below wants a comma delimeted string - # that can go right through to the command. - kwargs['groups'] = ",".join(groups) - else: + if isinstance(groups, six.string_types): groups = groups.split(",") + # remove any white spaces in group names, most likely + # that came in as a string like: groups: group1, group2 + groups = [g.strip() for g in groups] + + # kwargs.items loop below wants a comma delimeted string + # that can go right through to the command. + kwargs['groups'] = ",".join(groups) + primary_group = kwargs.get('primary_group') if primary_group: groups.append(primary_group) @@ -413,10 +405,10 @@ class Distro(object): for group in groups: if not util.is_group(group): self.create_group(group) - LOG.debug("created group %s for user %s", name, group) + LOG.debug("created group '%s' for user '%s'", group, name) # Check the values and create the command - for key, val in kwargs.items(): + for key, val in sorted(kwargs.items()): if key in adduser_opts and val and isinstance(val, str): adduser_cmd.extend([adduser_opts[key], val]) @@ -433,7 +425,7 @@ class Distro(object): # Don't create the home directory if directed so or if the user is a # system user - if 'no_create_home' in kwargs or 'system' in kwargs: + if kwargs.get('no_create_home') or kwargs.get('system'): adduser_cmd.append('-M') log_adduser_cmd.append('-M') else: @@ -744,3 +736,5 @@ def set_etc_timezone(tz, tz_file=None, tz_conf="/etc/timezone", else: util.copy(tz_file, tz_local) return + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/arch.py b/cloudinit/distros/arch.py index 66209f22..64b8c1fb 100644 --- a/cloudinit/distros/arch.py +++ b/cloudinit/distros/arch.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2014 Rackspace, US Inc. -# -# Author: Nate House <nathan.house@rackspace.com> +# Copyright (C) 2014 Rackspace, US Inc. # -# 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. +# Author: Nate House <nathan.house@rackspace.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit import distros from cloudinit import helpers @@ -199,3 +187,5 @@ def convert_resolv_conf(settings): for ns in settings: result = result + 'nameserver %s\n' % ns return result + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/debian.py b/cloudinit/distros/debian.py index f9b3b92e..48ccec8c 100644 --- a/cloudinit/distros/debian.py +++ b/cloudinit/distros/debian.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import os @@ -234,3 +222,5 @@ def _maybe_remove_legacy_eth0(path="/etc/network/interfaces.d/eth0.cfg"): msg = bmsg + " %s exists, but could not be read." % path LOG.warn(msg) + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/fedora.py b/cloudinit/distros/fedora.py index c777845d..a9490d0e 100644 --- a/cloudinit/distros/fedora.py +++ b/cloudinit/distros/fedora.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit.distros import rhel @@ -29,3 +17,5 @@ LOG = logging.getLogger(__name__) class Distro(rhel.Distro): pass + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/freebsd.py b/cloudinit/distros/freebsd.py index 91bf4a4e..a70ee45b 100644 --- a/cloudinit/distros/freebsd.py +++ b/cloudinit/distros/freebsd.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2014 Harm Weites -# -# Author: Harm Weites <harm@weites.com> +# Copyright (C) 2014 Harm Weites # -# 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. +# Author: Harm Weites <harm@weites.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import os import six @@ -415,3 +403,5 @@ class Distro(distros.Distro): def update_package_sources(self): self._runner.run("update-sources", self.package_command, ["update"], freq=PER_INSTANCE) + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/gentoo.py b/cloudinit/distros/gentoo.py index 1865dc69..83fb56ff 100644 --- a/cloudinit/distros/gentoo.py +++ b/cloudinit/distros/gentoo.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2014 Rackspace, US Inc. -# Copyright (C) 2016 Matthew Thode. -# -# Author: Nate House <nathan.house@rackspace.com> -# Author: Matthew Thode <prometheanfire@gentoo.org> +# Copyright (C) 2014 Rackspace, US Inc. +# Copyright (C) 2016 Matthew Thode. # -# 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. +# Author: Nate House <nathan.house@rackspace.com> +# Author: Matthew Thode <prometheanfire@gentoo.org> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit import distros from cloudinit import helpers @@ -233,3 +221,5 @@ def convert_resolv_conf(settings): for ns in settings: result += 'nameserver %s\n' % ns return result + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/net_util.py b/cloudinit/distros/net_util.py index cadfa6b6..1ce1aa71 100644 --- a/cloudinit/distros/net_util.py +++ b/cloudinit/distros/net_util.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. # This is a util function to translate debian based distro interface blobs as @@ -180,3 +168,5 @@ def translate_network(settings): if cmd == 'iface' and 'inet6' in args: real_ifaces[dev_name]['inet6'] = True return real_ifaces + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/parsers/__init__.py b/cloudinit/distros/parsers/__init__.py index 1c413eaa..6b5b6dde 100644 --- a/cloudinit/distros/parsers/__init__.py +++ b/cloudinit/distros/parsers/__init__.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. def chop_comment(text, comment_chars): @@ -26,3 +14,5 @@ def chop_comment(text, comment_chars): before_comment = text[0:min_comment] comment = text[min_comment:] return (before_comment, comment) + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/parsers/hostname.py b/cloudinit/distros/parsers/hostname.py index efb185d4..dd434ac6 100644 --- a/cloudinit/distros/parsers/hostname.py +++ b/cloudinit/distros/parsers/hostname.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from six import StringIO @@ -86,3 +74,5 @@ class HostnameConf(object): raise IOError("Multiple hostnames (%s) found!" % (hostnames_found)) return entries + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/parsers/hosts.py b/cloudinit/distros/parsers/hosts.py index 3c5498ee..87f164be 100644 --- a/cloudinit/distros/parsers/hosts.py +++ b/cloudinit/distros/parsers/hosts.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from six import StringIO @@ -90,3 +78,5 @@ class HostsConf(object): pieces = "\t".join(pieces) contents.write("%s%s\n" % (pieces, tail)) return contents.getvalue() + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/parsers/resolv_conf.py b/cloudinit/distros/parsers/resolv_conf.py index 2ed13d9c..ff6ee307 100644 --- a/cloudinit/distros/parsers/resolv_conf.py +++ b/cloudinit/distros/parsers/resolv_conf.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from six import StringIO @@ -167,3 +155,5 @@ class ResolvConf(object): raise IOError("Unexpected resolv.conf option %s" % (cfg_opt)) entries.append(("option", [cfg_opt, cfg_values, tail])) return entries + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/parsers/sys_conf.py b/cloudinit/distros/parsers/sys_conf.py index 6157cf32..c27b5d5d 100644 --- a/cloudinit/distros/parsers/sys_conf.py +++ b/cloudinit/distros/parsers/sys_conf.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import six from six import StringIO @@ -111,3 +99,5 @@ class SysConf(configobj.ConfigObj): self._a_to_u('='), val, cmnt) + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/rhel.py b/cloudinit/distros/rhel.py index e574e1b9..aa558381 100644 --- a/cloudinit/distros/rhel.py +++ b/cloudinit/distros/rhel.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit import distros from cloudinit import helpers @@ -229,3 +217,5 @@ class Distro(distros.Distro): def update_package_sources(self): self._runner.run("update-sources", self.package_command, ["makecache"], freq=PER_INSTANCE) + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/rhel_util.py b/cloudinit/distros/rhel_util.py index 903d7793..387a851f 100644 --- a/cloudinit/distros/rhel_util.py +++ b/cloudinit/distros/rhel_util.py @@ -1,25 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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. +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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 <http://www.gnu.org/licenses/>. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit.distros.parsers.resolv_conf import ResolvConf from cloudinit.distros.parsers.sys_conf import SysConf @@ -87,3 +74,5 @@ def update_resolve_conf_file(fn, dns_servers, search_servers): except ValueError: util.logexc(LOG, "Failed at adding search domain %s", s) util.write_file(fn, str(r_conf), 0o644) + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/sles.py b/cloudinit/distros/sles.py index 620c974c..dbec2edf 100644 --- a/cloudinit/distros/sles.py +++ b/cloudinit/distros/sles.py @@ -1,22 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# -# Leaning very heavily on the RHEL and Debian implementation +# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit import distros @@ -177,3 +163,5 @@ class Distro(distros.Distro): def update_package_sources(self): self._runner.run("update-sources", self.package_command, ['refresh'], freq=PER_INSTANCE) + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/ubuntu.py b/cloudinit/distros/ubuntu.py index c527f248..82ca34f5 100644 --- a/cloudinit/distros/ubuntu.py +++ b/cloudinit/distros/ubuntu.py @@ -1,25 +1,13 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# Author: Ben Howard <ben.howard@canonical.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Author: Ben Howard <ben.howard@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit.distros import debian from cloudinit import log as logging @@ -29,3 +17,5 @@ LOG = logging.getLogger(__name__) class Distro(debian.Distro): pass + +# vi: ts=4 expandtab diff --git a/cloudinit/distros/ug_util.py b/cloudinit/distros/ug_util.py index 99301530..53a0eafb 100755 --- a/cloudinit/distros/ug_util.py +++ b/cloudinit/distros/ug_util.py @@ -1,25 +1,13 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# Author: Ben Howard <ben.howard@canonical.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Author: Ben Howard <ben.howard@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import six @@ -297,3 +285,5 @@ def extract_default(users, default_name=None, default_config=None): config = tmp_users[name] config.pop('default', None) return (name, config) + +# vi: ts=4 expandtab diff --git a/cloudinit/ec2_utils.py b/cloudinit/ec2_utils.py index 76dda042..c656ef14 100644 --- a/cloudinit/ec2_utils.py +++ b/cloudinit/ec2_utils.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import functools import json @@ -57,8 +45,8 @@ class MetadataLeafDecoder(object): return blob -# See: http://bit.ly/TyoUQs -# +# See: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ +# ec2-instance-metadata.html class MetadataMaterializer(object): def __init__(self, blob, base_url, caller, leaf_decoder=None): self._blob = blob @@ -199,3 +187,5 @@ def get_instance_metadata(api_version='latest', except Exception: util.logexc(LOG, "Failed fetching metadata from url %s", md_url) return {} + +# vi: ts=4 expandtab diff --git a/cloudinit/filters/__init__.py b/cloudinit/filters/__init__.py index da124641..e69de29b 100644 --- a/cloudinit/filters/__init__.py +++ b/cloudinit/filters/__init__.py @@ -1,21 +0,0 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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 <http://www.gnu.org/licenses/>. diff --git a/cloudinit/filters/launch_index.py b/cloudinit/filters/launch_index.py index baecdac9..5c8bcffb 100644 --- a/cloudinit/filters/launch_index.py +++ b/cloudinit/filters/launch_index.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import copy @@ -73,3 +61,5 @@ class Filter(object): if self.wanted_idx is None: return root_message return self._do_filter(root_message) + +# vi: ts=4 expandtab diff --git a/cloudinit/gpg.py b/cloudinit/gpg.py index 5bbff513..70c620de 100644 --- a/cloudinit/gpg.py +++ b/cloudinit/gpg.py @@ -1,22 +1,11 @@ -"""gpg.py - Collection of gpg key related functions""" -# vi: ts=4 expandtab -# -# Copyright (C) 2016 Canonical Ltd. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Christian Ehrhardt <christian.ehrhardt@canonical.com> -# -# 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. +# Copyright (C) 2016 Canonical Ltd. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Christian Ehrhardt <christian.ehrhardt@canonical.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. + +"""gpg.py - Collection of gpg key related functions""" from cloudinit import log as logging from cloudinit import util @@ -72,3 +61,5 @@ def getkeybyid(keyid, keyserver='keyserver.ubuntu.com'): delete_key(keyid) return armour + +# vi: ts=4 expandtab diff --git a/cloudinit/handlers/__init__.py b/cloudinit/handlers/__init__.py index b6c43ce8..1362db6e 100644 --- a/cloudinit/handlers/__init__.py +++ b/cloudinit/handlers/__init__.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import abc import os @@ -272,3 +260,5 @@ def type_from_starts_with(payload, default=None): if payload_lc.startswith(text): return INCLUSION_TYPES_MAP[text] return default + +# vi: ts=4 expandtab diff --git a/cloudinit/handlers/boot_hook.py b/cloudinit/handlers/boot_hook.py index a4ea47ac..057b4dbc 100644 --- a/cloudinit/handlers/boot_hook.py +++ b/cloudinit/handlers/boot_hook.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import os @@ -68,3 +56,5 @@ class BootHookPartHandler(handlers.Handler): except Exception: util.logexc(LOG, "Boothooks unknown error when running %s", filepath) + +# vi: ts=4 expandtab diff --git a/cloudinit/handlers/cloud_config.py b/cloudinit/handlers/cloud_config.py index cad4dc0f..178a5b9b 100644 --- a/cloudinit/handlers/cloud_config.py +++ b/cloudinit/handlers/cloud_config.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import jsonpatch @@ -161,3 +149,5 @@ class CloudConfigPartHandler(handlers.Handler): except Exception: util.logexc(LOG, "Failed at merging in cloud config part from %s", filename) + +# vi: ts=4 expandtab diff --git a/cloudinit/handlers/shell_script.py b/cloudinit/handlers/shell_script.py index b5087693..e4945a23 100644 --- a/cloudinit/handlers/shell_script.py +++ b/cloudinit/handlers/shell_script.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import os @@ -53,3 +41,5 @@ class ShellScriptPartHandler(handlers.Handler): payload = util.dos2unix(payload) path = os.path.join(self.script_dir, filename) util.write_file(path, payload, 0o700) + +# vi: ts=4 expandtab diff --git a/cloudinit/handlers/upstart_job.py b/cloudinit/handlers/upstart_job.py index 309af91e..1ca92d4b 100644 --- a/cloudinit/handlers/upstart_job.py +++ b/cloudinit/handlers/upstart_job.py @@ -1,25 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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. +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - +# This file is part of cloud-init. See LICENSE file for license information. import os import re @@ -118,3 +105,5 @@ def _has_suitable_upstart(): SUITABLE_UPSTART = _has_suitable_upstart() + +# vi: ts=4 expandtab diff --git a/cloudinit/helpers.py b/cloudinit/helpers.py index fb95babc..4528fb01 100644 --- a/cloudinit/helpers.py +++ b/cloudinit/helpers.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from time import time @@ -458,3 +446,5 @@ class DefaultingConfigParser(RawConfigParser): if header: contents = "\n".join([header, contents]) return contents + +# vi: ts=4 expandtab diff --git a/cloudinit/importer.py b/cloudinit/importer.py index fb57253c..f1194fbe 100644 --- a/cloudinit/importer.py +++ b/cloudinit/importer.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import sys @@ -56,3 +44,5 @@ def find_module(base_name, search_paths, required_attrs=None): if found_attrs == len(required_attrs): found_paths.append(full_path) return (found_paths, lookup_paths) + +# vi: ts=4 expandtab diff --git a/cloudinit/log.py b/cloudinit/log.py index 3c79b9c9..3861709e 100644 --- a/cloudinit/log.py +++ b/cloudinit/log.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import logging import logging.config @@ -153,3 +141,5 @@ def resetLogging(): resetLogging() + +# vi: ts=4 expandtab diff --git a/cloudinit/mergers/__init__.py b/cloudinit/mergers/__init__.py index e13f55ac..7fbc25ff 100644 --- a/cloudinit/mergers/__init__.py +++ b/cloudinit/mergers/__init__.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import re @@ -164,3 +152,5 @@ def construct(parsed_mergers): for (attr, opts) in mergers_to_be: mergers.append(attr(root, opts)) return root + +# vi: ts=4 expandtab diff --git a/cloudinit/mergers/m_dict.py b/cloudinit/mergers/m_dict.py index 87cf1a72..6c5fddc2 100644 --- a/cloudinit/mergers/m_dict.py +++ b/cloudinit/mergers/m_dict.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import six @@ -86,3 +74,5 @@ class Merger(object): else: raise NotImplementedError("Unknown merge type %s" % (self._method)) return merged + +# vi: ts=4 expandtab diff --git a/cloudinit/mergers/m_list.py b/cloudinit/mergers/m_list.py index 81e5c580..daa0469a 100644 --- a/cloudinit/mergers/m_list.py +++ b/cloudinit/mergers/m_list.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import six @@ -87,3 +75,5 @@ class Merger(object): for i in range(0, common_len): merged_list[i] = merge_same_index(merged_list[i], merge_with[i]) return merged_list + +# vi: ts=4 expandtab diff --git a/cloudinit/mergers/m_str.py b/cloudinit/mergers/m_str.py index b00c4bf3..629df58e 100644 --- a/cloudinit/mergers/m_str.py +++ b/cloudinit/mergers/m_str.py @@ -1,21 +1,8 @@ -# -*- coding: utf-8 -*- -# vi: ts=4 expandtab -# # Copyright (C) 2012 Yahoo! Inc. # # Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import six @@ -44,3 +31,5 @@ class Merger(object): return value + six.text_type(merge_with) else: return value + six.binary_type(merge_with) + +# vi: ts=4 expandtab diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py index 7e58bfea..ea649cc2 100644..100755 --- a/cloudinit/net/__init__.py +++ b/cloudinit/net/__init__.py @@ -1,20 +1,9 @@ -# Copyright (C) 2013-2014 Canonical Ltd. +# Copyright (C) 2013-2014 Canonical Ltd. # -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Blake Rouse <blake.rouse@canonical.com> +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Blake Rouse <blake.rouse@canonical.com> # -# Curtin is free software: you can redistribute it and/or modify it under -# the terms of the GNU Affero General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# Curtin 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 Affero General Public License for -# more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Curtin. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import errno import logging @@ -32,25 +21,53 @@ def sys_dev_path(devname, path=""): return SYS_CLASS_NET + devname + "/" + path -def read_sys_net(devname, path, translate=None, enoent=None, keyerror=None): +def read_sys_net(devname, path, translate=None, + on_enoent=None, on_keyerror=None, + on_einval=None): + dev_path = sys_dev_path(devname, path) try: - contents = util.load_file(sys_dev_path(devname, path)) + contents = util.load_file(dev_path) except (OSError, IOError) as e: - if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR): - if enoent is not None: - return enoent + e_errno = getattr(e, 'errno', None) + if e_errno in (errno.ENOENT, errno.ENOTDIR): + if on_enoent is not None: + return on_enoent(e) + if e_errno in (errno.EINVAL,): + if on_einval is not None: + return on_einval(e) raise contents = contents.strip() if translate is None: return contents try: - return translate.get(contents) - except KeyError: - LOG.debug("found unexpected value '%s' in '%s/%s'", contents, - devname, path) - if keyerror is not None: - return keyerror - raise + return translate[contents] + except KeyError as e: + if on_keyerror is not None: + return on_keyerror(e) + else: + LOG.debug("Found unexpected (not translatable) value" + " '%s' in '%s", contents, dev_path) + raise + + +def read_sys_net_safe(iface, field, translate=None): + def on_excp_false(e): + return False + return read_sys_net(iface, field, + on_keyerror=on_excp_false, + on_enoent=on_excp_false, + on_einval=on_excp_false, + translate=translate) + + +def read_sys_net_int(iface, field): + val = read_sys_net_safe(iface, field) + if val is False: + return None + try: + return int(val) + except TypeError: + return None def is_up(devname): @@ -58,8 +75,7 @@ def is_up(devname): # operstate as up for the purposes of network configuration. See # Documentation/networking/operstates.txt in the kernel source. translate = {'up': True, 'unknown': True, 'down': False} - return read_sys_net(devname, "operstate", enoent=False, keyerror=False, - translate=translate) + return read_sys_net_safe(devname, "operstate", translate=translate) def is_wireless(devname): @@ -70,21 +86,14 @@ def is_connected(devname): # is_connected isn't really as simple as that. 2 is # 'physically connected'. 3 is 'not connected'. but a wlan interface will # always show 3. - try: - iflink = read_sys_net(devname, "iflink", enoent=False) - if iflink == "2": - return True - if not is_wireless(devname): - return False - LOG.debug("'%s' is wireless, basing 'connected' on carrier", devname) - - return read_sys_net(devname, "carrier", enoent=False, keyerror=False, - translate={'0': False, '1': True}) - - except IOError as e: - if e.errno == errno.EINVAL: - return False - raise + iflink = read_sys_net_safe(devname, "iflink") + if iflink == "2": + return True + if not is_wireless(devname): + return False + LOG.debug("'%s' is wireless, basing 'connected' on carrier", devname) + return read_sys_net_safe(devname, "carrier", + translate={'0': False, '1': True}) def is_physical(devname): @@ -109,25 +118,9 @@ def is_disabled_cfg(cfg): return cfg.get('config') == "disabled" -def sys_netdev_info(name, field): - if not os.path.exists(os.path.join(SYS_CLASS_NET, name)): - raise OSError("%s: interface does not exist in %s" % - (name, SYS_CLASS_NET)) - fname = os.path.join(SYS_CLASS_NET, name, field) - if not os.path.exists(fname): - raise OSError("%s: could not find sysfs entry: %s" % (name, fname)) - data = util.load_file(fname) - if data[-1] == '\n': - data = data[:-1] - return data - - def generate_fallback_config(): """Determine which attached net dev is most likely to have a connection and generate network state to run dhcp on that interface""" - # by default use eth0 as primary interface - nconf = {'config': [], 'version': 1} - # get list of interfaces that could have connections invalid_interfaces = set(['lo']) potential_interfaces = set(get_devicelist()) @@ -142,30 +135,21 @@ def generate_fallback_config(): if os.path.exists(sys_dev_path(interface, "bridge")): # skip any bridges continue - try: - carrier = int(sys_netdev_info(interface, 'carrier')) - if carrier: - connected.append(interface) - continue - except OSError: - pass + carrier = read_sys_net_int(interface, 'carrier') + if carrier: + connected.append(interface) + continue # check if nic is dormant or down, as this may make a nick appear to # not have a carrier even though it could acquire one when brought # online by dhclient - try: - dormant = int(sys_netdev_info(interface, 'dormant')) - if dormant: - possibly_connected.append(interface) - continue - except OSError: - pass - try: - operstate = sys_netdev_info(interface, 'operstate') - if operstate in ['dormant', 'down', 'lowerlayerdown', 'unknown']: - possibly_connected.append(interface) - continue - except OSError: - pass + dormant = read_sys_net_int(interface, 'dormant') + if dormant: + possibly_connected.append(interface) + continue + operstate = read_sys_net_safe(interface, 'operstate') + if operstate in ['dormant', 'down', 'lowerlayerdown', 'unknown']: + possibly_connected.append(interface) + continue # don't bother with interfaces that might not be connected if there are # some that definitely are @@ -173,23 +157,30 @@ def generate_fallback_config(): potential_interfaces = connected else: potential_interfaces = possibly_connected - # if there are no interfaces, give up - if not potential_interfaces: - return + # if eth0 exists use it above anything else, otherwise get the interface - # that looks 'first' - if DEFAULT_PRIMARY_INTERFACE in potential_interfaces: - name = DEFAULT_PRIMARY_INTERFACE + # that we can read 'first' (using the sorted defintion of first). + names = list(sorted(potential_interfaces)) + if DEFAULT_PRIMARY_INTERFACE in names: + names.remove(DEFAULT_PRIMARY_INTERFACE) + names.insert(0, DEFAULT_PRIMARY_INTERFACE) + target_name = None + target_mac = None + for name in names: + mac = read_sys_net_safe(name, 'address') + if mac: + target_name = name + target_mac = mac + break + if target_mac and target_name: + nconf = {'config': [], 'version': 1} + nconf['config'].append( + {'type': 'physical', 'name': target_name, + 'mac_address': target_mac, 'subnets': [{'type': 'dhcp'}]}) + return nconf else: - name = sorted(potential_interfaces)[0] - - mac = sys_netdev_info(name, 'address') - target_name = name - - nconf['config'].append( - {'type': 'physical', 'name': target_name, - 'mac_address': mac, 'subnets': [{'type': 'dhcp'}]}) - return nconf + # can't read any interfaces addresses (or there are none); give up + return None def apply_network_config_names(netcfg, strict_present=True, strict_busy=True): @@ -352,7 +343,7 @@ def get_interface_mac(ifname): # for a bond slave, get the nic's hwaddress, not the address it # is using because its part of a bond. path = "bonding_slave/perm_hwaddr" - return read_sys_net(ifname, path, enoent=False) + return read_sys_net_safe(ifname, path) def get_interfaces_by_mac(devs=None): @@ -373,4 +364,4 @@ def get_interfaces_by_mac(devs=None): ret[mac] = name return ret -# vi: ts=4 expandtab syntax=python +# vi: ts=4 expandtab diff --git a/cloudinit/net/cmdline.py b/cloudinit/net/cmdline.py index 4075a279..7c5d11a7 100644..100755 --- a/cloudinit/net/cmdline.py +++ b/cloudinit/net/cmdline.py @@ -1,20 +1,9 @@ -# Copyright (C) 2013-2014 Canonical Ltd. +# Copyright (C) 2013-2014 Canonical Ltd. # -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Blake Rouse <blake.rouse@canonical.com> +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Blake Rouse <blake.rouse@canonical.com> # -# Curtin is free software: you can redistribute it and/or modify it under -# the terms of the GNU Affero General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# Curtin 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 Affero General Public License for -# more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Curtin. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import base64 import glob @@ -26,7 +15,7 @@ import sys import six from . import get_devicelist -from . import sys_netdev_info +from . import read_sys_net_safe from cloudinit import util @@ -57,7 +46,7 @@ def _load_shell_content(content, add_empty=False, empty_val=None): def _klibc_to_config_entry(content, mac_addrs=None): - """Convert a klibc writtent shell content file to a 'config' entry + """Convert a klibc written shell content file to a 'config' entry When ip= is seen on the kernel command line in debian initramfs and networking is brought up, ipconfig will populate /run/net-<name>.cfg. @@ -140,7 +129,7 @@ def _klibc_to_config_entry(content, mac_addrs=None): def config_from_klibc_net_cfg(files=None, mac_addrs=None): if files is None: - files = glob.glob('/run/net*.conf') + files = glob.glob('/run/net-*.conf') + glob.glob('/run/net6-*.conf') entries = [] names = {} @@ -148,12 +137,19 @@ def config_from_klibc_net_cfg(files=None, mac_addrs=None): name, entry = _klibc_to_config_entry(util.load_file(cfg_file), mac_addrs=mac_addrs) if name in names: - raise ValueError( - "device '%s' defined multiple times: %s and %s" % ( - name, names[name], cfg_file)) + prev = names[name]['entry'] + if prev.get('mac_address') != entry.get('mac_address'): + raise ValueError( + "device '%s' was defined multiple times (%s)" + " but had differing mac addresses: %s -> %s.", + (name, ' '.join(names[name]['files']), + prev.get('mac_address'), entry.get('mac_address'))) + prev['subnets'].extend(entry['subnets']) + names[name]['files'].append(cfg_file) + else: + names[name] = {'files': [cfg_file], 'entry': entry} + entries.append(entry) - names[name] = cfg_file - entries.append(entry) return {'config': entries, 'version': 1} @@ -199,11 +195,16 @@ def read_kernel_cmdline_config(files=None, mac_addrs=None, cmdline=None): if data64: return util.load_yaml(_b64dgz(data64)) - if 'ip=' not in cmdline: + if 'ip=' not in cmdline and 'ip6=' not in cmdline: return None if mac_addrs is None: - mac_addrs = dict((k, sys_netdev_info(k, 'address')) - for k in get_devicelist()) + mac_addrs = {} + for k in get_devicelist(): + mac_addr = read_sys_net_safe(k, 'address') + if mac_addr: + mac_addrs[k] = mac_addr return config_from_klibc_net_cfg(files=files, mac_addrs=mac_addrs) + +# vi: ts=4 expandtab diff --git a/cloudinit/net/eni.py b/cloudinit/net/eni.py index cd533ddb..b06ffac9 100644 --- a/cloudinit/net/eni.py +++ b/cloudinit/net/eni.py @@ -1,16 +1,4 @@ -# vi: ts=4 expandtab -# -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import copy import glob @@ -502,3 +490,5 @@ def network_state_to_eni(network_state, header=None, render_hwaddress=False): contents = renderer._render_interfaces( network_state, render_hwaddress=render_hwaddress) return header + contents + +# vi: ts=4 expandtab diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py index 8ca5106f..11ef585b 100644 --- a/cloudinit/net/network_state.py +++ b/cloudinit/net/network_state.py @@ -1,19 +1,8 @@ -# Copyright (C) 2013-2014 Canonical Ltd. +# Copyright (C) 2013-2014 Canonical Ltd. # -# Author: Ryan Harper <ryan.harper@canonical.com> +# Author: Ryan Harper <ryan.harper@canonical.com> # -# Curtin is free software: you can redistribute it and/or modify it under -# the terms of the GNU Affero General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# Curtin 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 Affero General Public License for -# more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Curtin. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import copy import functools @@ -452,3 +441,5 @@ def mask2cidr(mask): return ipv4mask2cidr(mask) else: return mask + +# vi: ts=4 expandtab diff --git a/cloudinit/net/renderer.py b/cloudinit/net/renderer.py index 310cbe0d..3a192436 100644 --- a/cloudinit/net/renderer.py +++ b/cloudinit/net/renderer.py @@ -1,20 +1,9 @@ -# Copyright (C) 2013-2014 Canonical Ltd. +# Copyright (C) 2013-2014 Canonical Ltd. # -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Blake Rouse <blake.rouse@canonical.com> +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Blake Rouse <blake.rouse@canonical.com> # -# Curtin is free software: you can redistribute it and/or modify it under -# the terms of the GNU Affero General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# Curtin 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 Affero General Public License for -# more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Curtin. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import six @@ -46,3 +35,5 @@ class Renderer(object): content.write(generate_udev_rule(iface['name'], iface['mac_address'])) return content.getvalue() + +# vi: ts=4 expandtab diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py index c53acf71..9be74070 100644 --- a/cloudinit/net/sysconfig.py +++ b/cloudinit/net/sysconfig.py @@ -1,16 +1,4 @@ -# vi: ts=4 expandtab -# -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import os import re @@ -398,3 +386,5 @@ class Renderer(renderer.Renderer): netrules_content = self._render_persistent_net(network_state) netrules_path = os.path.join(target, self.netrules_path) util.write_file(netrules_path, netrules_content) + +# vi: ts=4 expandtab diff --git a/cloudinit/net/udev.py b/cloudinit/net/udev.py index 09188295..fd2fd8c7 100644 --- a/cloudinit/net/udev.py +++ b/cloudinit/net/udev.py @@ -1,19 +1,8 @@ -# Copyright (C) 2015 Canonical Ltd. +# Copyright (C) 2015 Canonical Ltd. # -# Author: Ryan Harper <ryan.harper@canonical.com> +# Author: Ryan Harper <ryan.harper@canonical.com> # -# Curtin is free software: you can redistribute it and/or modify it under -# the terms of the GNU Affero General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# Curtin 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 Affero General Public License for -# more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with Curtin. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. def compose_udev_equality(key, value): diff --git a/cloudinit/netinfo.py b/cloudinit/netinfo.py index d8698a5d..ed374a36 100644 --- a/cloudinit/netinfo.py +++ b/cloudinit/netinfo.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import re @@ -247,3 +235,5 @@ def debug_info(prefix='ci-info: '): else: lines.extend(route_lines) return "\n".join(lines) + +# vi: ts=4 expandtab diff --git a/cloudinit/patcher.py b/cloudinit/patcher.py index f6609d6f..2df9441a 100644 --- a/cloudinit/patcher.py +++ b/cloudinit/patcher.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import imp import logging @@ -56,3 +44,5 @@ def patch(): _patch_logging() finally: imp.release_lock() + +# vi: ts=4 expandtab diff --git a/cloudinit/registry.py b/cloudinit/registry.py index 04368ddf..8e495641 100644 --- a/cloudinit/registry.py +++ b/cloudinit/registry.py @@ -1,7 +1,7 @@ -# Copyright 2015 Canonical Ltd. -# This file is part of cloud-init. See LICENCE file for license information. +# Copyright (C) 2015 Canonical Ltd. # -# vi: ts=4 expandtab +# This file is part of cloud-init. See LICENSE file for license information. + import copy @@ -35,3 +35,5 @@ class DictRegistry(object): This cannot be used to modify the contents of the registry. """ return copy.copy(self._items) + +# vi: ts=4 expandtab diff --git a/cloudinit/reporting/__init__.py b/cloudinit/reporting/__init__.py index 6b41ae61..1ed2b487 100644 --- a/cloudinit/reporting/__init__.py +++ b/cloudinit/reporting/__init__.py @@ -1,6 +1,7 @@ -# Copyright 2015 Canonical Ltd. -# This file is part of cloud-init. See LICENCE file for license information. +# Copyright (C) 2015 Canonical Ltd. # +# This file is part of cloud-init. See LICENSE file for license information. + """ cloud-init reporting framework diff --git a/cloudinit/reporting/events.py b/cloudinit/reporting/events.py index df2b9b4a..4f62d2f9 100644 --- a/cloudinit/reporting/events.py +++ b/cloudinit/reporting/events.py @@ -1,6 +1,7 @@ -# Copyright 2015 Canonical Ltd. -# This file is part of cloud-init. See LICENCE file for license information. +# Copyright (C) 2015 Canonical Ltd. # +# This file is part of cloud-init. See LICENSE file for license information. + """ events for reporting. @@ -245,4 +246,4 @@ def _collect_file_info(files): 'encoding': 'base64'}) return ret -# vi: ts=4 expandtab syntax=python +# vi: ts=4 expandtab diff --git a/cloudinit/reporting/handlers.py b/cloudinit/reporting/handlers.py index dff20ecb..b90bc191 100644 --- a/cloudinit/reporting/handlers.py +++ b/cloudinit/reporting/handlers.py @@ -1,4 +1,4 @@ -# vi: ts=4 expandtab +# This file is part of cloud-init. See LICENSE file for license information. import abc import json @@ -89,3 +89,5 @@ available_handlers = DictRegistry() available_handlers.register_item('log', LogHandler) available_handlers.register_item('print', PrintHandler) available_handlers.register_item('webhook', WebHookHandler) + +# vi: ts=4 expandtab diff --git a/cloudinit/safeyaml.py b/cloudinit/safeyaml.py index f6a3f765..7bcf9dd3 100644 --- a/cloudinit/safeyaml.py +++ b/cloudinit/safeyaml.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# -# Author: Scott Moser <scott.moser@canonical.com> +# Copyright (C) 2012 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. +# Author: Scott Moser <scott.moser@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import yaml @@ -31,3 +19,5 @@ _CustomSafeLoader.add_constructor( def load(blob): return(yaml.load(blob, Loader=_CustomSafeLoader)) + +# vi: ts=4 expandtab diff --git a/cloudinit/serial.py b/cloudinit/serial.py index af45c13e..f9ef7acc 100644 --- a/cloudinit/serial.py +++ b/cloudinit/serial.py @@ -1,17 +1,4 @@ -# vi: ts=4 expandtab -# -# 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 <http://www.gnu.org/licenses/>. - +# This file is part of cloud-init. See LICENSE file for license information. from __future__ import absolute_import @@ -48,3 +35,5 @@ except ImportError: def read(size=1): raise IOError("Unable to perform serial `read` operation," " pyserial not installed.") + +# vi: ts=4 expandtab diff --git a/cloudinit/settings.py b/cloudinit/settings.py index a9682716..b1fdd31f 100644 --- a/cloudinit/settings.py +++ b/cloudinit/settings.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. # Set and read for determining the cloud config file location CFG_ENV_NAME = "CLOUD_CFG" @@ -67,3 +55,5 @@ PER_ONCE = "once" # Used to sanity check incoming handlers/modules frequencies FREQUENCIES = [PER_INSTANCE, PER_ALWAYS, PER_ONCE] + +# vi: ts=4 expandtab diff --git a/cloudinit/signal_handler.py b/cloudinit/signal_handler.py index d76223d1..12fdfe6c 100644 --- a/cloudinit/signal_handler.py +++ b/cloudinit/signal_handler.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import inspect import signal @@ -69,3 +57,5 @@ def attach_handlers(): signal.signal(signum, _handle_exit) sigs_attached += len(EXIT_FOR) return sigs_attached + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceAliYun.py b/cloudinit/sources/DataSourceAliYun.py index 535813ab..2d00255c 100644 --- a/cloudinit/sources/DataSourceAliYun.py +++ b/cloudinit/sources/DataSourceAliYun.py @@ -1,4 +1,4 @@ -# vi: ts=4 expandtab +# This file is part of cloud-init. See LICENSE file for license information. import os @@ -48,3 +48,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceAltCloud.py b/cloudinit/sources/DataSourceAltCloud.py index fac7bbcc..c2b0eac2 100644 --- a/cloudinit/sources/DataSourceAltCloud.py +++ b/cloudinit/sources/DataSourceAltCloud.py @@ -1,23 +1,11 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joe VLcek <JVLcek@RedHat.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joe VLcek <JVLcek@RedHat.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. ''' This file contains code used to gather the user data passed to an @@ -283,3 +271,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py index 22f9004a..c5af8b84 100644 --- a/cloudinit/sources/DataSourceAzure.py +++ b/cloudinit/sources/DataSourceAzure.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2013 Canonical Ltd. -# -# Author: Scott Moser <scott.moser@canonical.com> +# Copyright (C) 2013 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. +# Author: Scott Moser <scott.moser@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import base64 import contextlib @@ -36,6 +24,7 @@ LOG = logging.getLogger(__name__) DS_NAME = 'Azure' DEFAULT_METADATA = {"instance-id": "iid-AZURE-NODE"} AGENT_START = ['service', 'walinuxagent', 'start'] +AGENT_START_BUILTIN = "__builtin__" BOUNCE_COMMAND = [ 'sh', '-xc', "i=$interface; x=0; ifdown $i || x=$?; ifup $i || x=$?; exit $x" @@ -45,7 +34,7 @@ BOUNCE_COMMAND = [ RESOURCE_DISK_PATH = '/dev/disk/cloud/azure_resource' BUILTIN_DS_CONFIG = { - 'agent_command': AGENT_START, + 'agent_command': AGENT_START_BUILTIN, 'data_dir': "/var/lib/waagent", 'set_hostname': True, 'hostname_bounce': { @@ -230,7 +219,7 @@ class DataSourceAzureNet(sources.DataSource): # the directory to be protected. write_files(ddir, files, dirmode=0o700) - if self.ds_cfg['agent_command'] == '__builtin__': + if self.ds_cfg['agent_command'] == AGENT_START_BUILTIN: metadata_func = partial(get_metadata_from_fabric, fallback_lease_file=self. dhclient_lease_file) @@ -304,7 +293,7 @@ def can_dev_be_reformatted(devpath): return False, msg def count_files(mp): - ignored = {'dataloss_warning_readme.txt'} + ignored = set(['dataloss_warning_readme.txt']) return len([f for f in os.listdir(mp) if f.lower() not in ignored]) bmsg = ('partition 1 (%s -> %s) on device %s was ntfs formatted' % @@ -667,3 +656,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceBigstep.py b/cloudinit/sources/DataSourceBigstep.py index e8fd0088..5ffdcb25 100644 --- a/cloudinit/sources/DataSourceBigstep.py +++ b/cloudinit/sources/DataSourceBigstep.py @@ -1,8 +1,8 @@ +# Copyright (C) 2015-2016 Bigstep Cloud Ltd. # -# Copyright (C) 2015-2016 Bigstep Cloud Ltd. -# -# Author: Alexandru Sirbu <alexandru.sirbu@bigstep.com> +# Author: Alexandru Sirbu <alexandru.sirbu@bigstep.com> # +# This file is part of cloud-init. See LICENSE file for license information. import errno import json @@ -56,3 +56,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceCloudSigma.py b/cloudinit/sources/DataSourceCloudSigma.py index be74503b..ffc23e3d 100644 --- a/cloudinit/sources/DataSourceCloudSigma.py +++ b/cloudinit/sources/DataSourceCloudSigma.py @@ -1,20 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2014 CloudSigma -# -# Author: Kiril Vladimiroff <kiril.vladimiroff@cloudsigma.com> -# -# 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. +# Copyright (C) 2014 CloudSigma # -# 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. +# Author: Kiril Vladimiroff <kiril.vladimiroff@cloudsigma.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. + from base64 import b64decode import re @@ -115,7 +104,7 @@ DataSourceCloudSigmaNet = DataSourceCloudSigma # Used to match classes to dependencies. Since this datasource uses the serial # port network is not really required, so it's okay to load without it, too. datasources = [ - (DataSourceCloudSigma, (sources.DEP_FILESYSTEM)), + (DataSourceCloudSigma, (sources.DEP_FILESYSTEM, )), ] @@ -124,3 +113,5 @@ def get_datasource_list(depends): Return a list of data sources that match this set of dependencies """ return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceCloudStack.py b/cloudinit/sources/DataSourceCloudStack.py index 4de1f563..b0ab275c 100644 --- a/cloudinit/sources/DataSourceCloudStack.py +++ b/cloudinit/sources/DataSourceCloudStack.py @@ -1,28 +1,16 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Cosmin Luta -# Copyright (C) 2012 Yahoo! Inc. -# Copyright (C) 2012 Gerard Dethier -# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Cosmin Luta <q4break@gmail.com> -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# Author: Gerard Dethier <g.dethier@gmail.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Cosmin Luta +# Copyright (C) 2012 Yahoo! Inc. +# Copyright (C) 2012 Gerard Dethier +# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Cosmin Luta <q4break@gmail.com> +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Author: Gerard Dethier <g.dethier@gmail.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import os from socket import inet_ntoa @@ -251,3 +239,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceConfigDrive.py b/cloudinit/sources/DataSourceConfigDrive.py index 5c9edabe..8a448dc9 100644 --- a/cloudinit/sources/DataSourceConfigDrive.py +++ b/cloudinit/sources/DataSourceConfigDrive.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import os @@ -276,3 +264,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceDigitalOcean.py b/cloudinit/sources/DataSourceDigitalOcean.py index c5770d5d..d052c4c3 100644 --- a/cloudinit/sources/DataSourceDigitalOcean.py +++ b/cloudinit/sources/DataSourceDigitalOcean.py @@ -1,19 +1,7 @@ -# vi: ts=4 expandtab -# -# Author: Neal Shrader <neal@digitalocean.com> -# Author: Ben Howard <bh@digitalocean.com> -# -# 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. +# Author: Neal Shrader <neal@digitalocean.com> +# Author: Ben Howard <bh@digitalocean.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. # DigitalOcean Droplet API: # https://developers.digitalocean.com/documentation/metadata/ @@ -121,3 +109,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py index acbc2356..c657fd09 100644 --- a/cloudinit/sources/DataSourceEc2.py +++ b/cloudinit/sources/DataSourceEc2.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Hafliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Hafliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import os import time @@ -212,3 +200,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceGCE.py b/cloudinit/sources/DataSourceGCE.py index 5ed59559..b1a1c8f2 100644 --- a/cloudinit/sources/DataSourceGCE.py +++ b/cloudinit/sources/DataSourceGCE.py @@ -1,19 +1,6 @@ -# vi: ts=4 expandtab -# -# Author: Vaidas Jablonskis <jablonskis@gmail.com> -# -# 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. +# Author: Vaidas Jablonskis <jablonskis@gmail.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - +# This file is part of cloud-init. See LICENSE file for license information. from base64 import b64decode @@ -166,3 +153,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceMAAS.py b/cloudinit/sources/DataSourceMAAS.py index 81abcd47..41179b02 100644 --- a/cloudinit/sources/DataSourceMAAS.py +++ b/cloudinit/sources/DataSourceMAAS.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from __future__ import print_function @@ -378,3 +366,5 @@ if __name__ == "__main__": crawl(args.url) main() + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceNoCloud.py b/cloudinit/sources/DataSourceNoCloud.py index e6a0b5fe..5924b828 100644 --- a/cloudinit/sources/DataSourceNoCloud.py +++ b/cloudinit/sources/DataSourceNoCloud.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Hafliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Hafliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import errno import os @@ -321,3 +309,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceNone.py b/cloudinit/sources/DataSourceNone.py index d1a62b2a..906bb278 100644 --- a/cloudinit/sources/DataSourceNone.py +++ b/cloudinit/sources/DataSourceNone.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit import log as logging from cloudinit import sources @@ -55,3 +43,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py index 5b3bdb4e..78928c77 100644 --- a/cloudinit/sources/DataSourceOVF.py +++ b/cloudinit/sources/DataSourceOVF.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2011 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Hafliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2011 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Hafliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from xml.dom import minidom @@ -427,3 +415,5 @@ datasources = ( # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceOpenNebula.py b/cloudinit/sources/DataSourceOpenNebula.py index ba5f3f92..1f1baf46 100644 --- a/cloudinit/sources/DataSourceOpenNebula.py +++ b/cloudinit/sources/DataSourceOpenNebula.py @@ -1,28 +1,16 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Yahoo! Inc. -# Copyright (C) 2012-2013 CERIT Scientific Cloud -# Copyright (C) 2012-2013 OpenNebula.org -# Copyright (C) 2014 Consejo Superior de Investigaciones Cientificas -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# Author: Vlastimil Holer <xholer@mail.muni.cz> -# Author: Javier Fontan <jfontan@opennebula.org> -# Author: Enol Fernandez <enolfc@ifca.unican.es> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Yahoo! Inc. +# Copyright (C) 2012-2013 CERIT Scientific Cloud +# Copyright (C) 2012-2013 OpenNebula.org +# Copyright (C) 2014 Consejo Superior de Investigaciones Cientificas # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Author: Vlastimil Holer <xholer@mail.muni.cz> +# Author: Javier Fontan <jfontan@opennebula.org> +# Author: Enol Fernandez <enolfc@ifca.unican.es> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import os import pwd @@ -423,3 +411,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceOpenStack.py b/cloudinit/sources/DataSourceOpenStack.py index 82558214..2a58f1cd 100644 --- a/cloudinit/sources/DataSourceOpenStack.py +++ b/cloudinit/sources/DataSourceOpenStack.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2014 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2014 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import time @@ -166,3 +154,5 @@ datasources = [ # Return a list of data sources that match this set of dependencies def get_datasource_list(depends): return sources.list_from_depends(depends, datasources) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/DataSourceSmartOS.py b/cloudinit/sources/DataSourceSmartOS.py index 143ab368..5e668947 100644 --- a/cloudinit/sources/DataSourceSmartOS.py +++ b/cloudinit/sources/DataSourceSmartOS.py @@ -1,22 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2013 Canonical Ltd. -# -# Author: Ben Howard <ben.howard@canonical.com> -# -# 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 <http://www.gnu.org/licenses/>. +# Copyright (C) 2013 Canonical Ltd. # +# Author: Ben Howard <ben.howard@canonical.com> # +# This file is part of cloud-init. See LICENSE file for license information. + # Datasource for provisioning on SmartOS. This works on Joyent # and public/private Clouds using SmartOS. # @@ -841,3 +828,5 @@ if __name__ == "__main__": print(json.dumps(data, indent=1, sort_keys=True, separators=(',', ': '))) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py index 13fb7c62..3d01072f 100644 --- a/cloudinit/sources/__init__.py +++ b/cloudinit/sources/__init__.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import abc import copy @@ -194,6 +182,8 @@ class DataSource(object): fqdn = util.get_fqdn_from_hosts(hostname) if fqdn and fqdn.find(".") > 0: toks = str(fqdn).split(".") + elif hostname and hostname.find(".") > 0: + toks = str(hostname).split(".") elif hostname: toks = [hostname, defdomain] else: @@ -406,3 +396,5 @@ def list_from_depends(depends, ds_list): if depset == set(deps): ret_list.append(cls) return ret_list + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/__init__.py b/cloudinit/sources/helpers/__init__.py index 386225d5..e69de29b 100644 --- a/cloudinit/sources/helpers/__init__.py +++ b/cloudinit/sources/helpers/__init__.py @@ -1,13 +0,0 @@ -# vi: ts=4 expandtab -# -# 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 <http://www.gnu.org/licenses/>. diff --git a/cloudinit/sources/helpers/azure.py b/cloudinit/sources/helpers/azure.py index 1b3e9b70..f32dac9a 100644 --- a/cloudinit/sources/helpers/azure.py +++ b/cloudinit/sources/helpers/azure.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import json import logging import os @@ -353,3 +355,5 @@ def get_metadata_from_fabric(fallback_lease_file=None): return shim.register_with_azure_and_fetch_data() finally: shim.clean_up() + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/digitalocean.py b/cloudinit/sources/helpers/digitalocean.py index b0a721c2..72f7bde4 100644 --- a/cloudinit/sources/helpers/digitalocean.py +++ b/cloudinit/sources/helpers/digitalocean.py @@ -1,18 +1,6 @@ -# vi: ts=4 expandtab -# -# Author: Ben Howard <bh@digitalocean.com> - -# 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. +# Author: Ben Howard <bh@digitalocean.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import json import random @@ -216,3 +204,5 @@ def read_sysinfo(): raise RuntimeError(msg) return (True, droplet_id) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/openstack.py b/cloudinit/sources/helpers/openstack.py index 61b0b08c..096062d5 100644 --- a/cloudinit/sources/helpers/openstack.py +++ b/cloudinit/sources/helpers/openstack.py @@ -1,22 +1,10 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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. +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import abc import base64 @@ -61,6 +49,19 @@ OS_VERSIONS = ( OS_LIBERTY, ) +PHYSICAL_TYPES = ( + None, + 'bridge', + 'ethernet', + 'hw_veb', + 'hyperv', + 'ovs', + 'phy', + 'tap', + 'vhostuser', + 'vif', +) + class NonReadable(IOError): pass @@ -583,8 +584,7 @@ def convert_net_json(network_json=None, known_macs=None): subnet['ipv6'] = True subnets.append(subnet) cfg.update({'subnets': subnets}) - if link['type'] in [None, 'ethernet', 'vif', 'ovs', 'phy', - 'bridge', 'tap']: + if link['type'] in PHYSICAL_TYPES: cfg.update({'type': 'physical', 'mac_address': link_mac_addr}) elif link['type'] in ['bond']: params = {} @@ -663,3 +663,5 @@ def convert_net_json(network_json=None, known_macs=None): config.append(cfg) return {'version': 1, 'config': config} + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/__init__.py b/cloudinit/sources/helpers/vmware/__init__.py index 386225d5..e69de29b 100644 --- a/cloudinit/sources/helpers/vmware/__init__.py +++ b/cloudinit/sources/helpers/vmware/__init__.py @@ -1,13 +0,0 @@ -# vi: ts=4 expandtab -# -# 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 <http://www.gnu.org/licenses/>. diff --git a/cloudinit/sources/helpers/vmware/imc/__init__.py b/cloudinit/sources/helpers/vmware/imc/__init__.py index 386225d5..e69de29b 100644 --- a/cloudinit/sources/helpers/vmware/imc/__init__.py +++ b/cloudinit/sources/helpers/vmware/imc/__init__.py @@ -1,13 +0,0 @@ -# vi: ts=4 expandtab -# -# 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 <http://www.gnu.org/licenses/>. diff --git a/cloudinit/sources/helpers/vmware/imc/boot_proto.py b/cloudinit/sources/helpers/vmware/imc/boot_proto.py index fb53ec1d..9a07eafa 100644 --- a/cloudinit/sources/helpers/vmware/imc/boot_proto.py +++ b/cloudinit/sources/helpers/vmware/imc/boot_proto.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Canonical Ltd. -# Copyright (C) 2015 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2015 Canonical Ltd. +# Copyright (C) 2015 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. class BootProtoEnum(object): @@ -23,3 +11,5 @@ class BootProtoEnum(object): DHCP = 'dhcp' STATIC = 'static' + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/config.py b/cloudinit/sources/helpers/vmware/imc/config.py index d645c497..9a5e3a8a 100644 --- a/cloudinit/sources/helpers/vmware/imc/config.py +++ b/cloudinit/sources/helpers/vmware/imc/config.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Canonical Ltd. -# Copyright (C) 2015 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2015 Canonical Ltd. +# Copyright (C) 2015 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from .nic import Nic @@ -93,3 +81,5 @@ class Config(object): res.append(Nic(nic, self._configFile)) return res + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/config_file.py b/cloudinit/sources/helpers/vmware/imc/config_file.py index bb9fb7dc..14293f3c 100644 --- a/cloudinit/sources/helpers/vmware/imc/config_file.py +++ b/cloudinit/sources/helpers/vmware/imc/config_file.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Canonical Ltd. -# Copyright (C) 2015 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2015 Canonical Ltd. +# Copyright (C) 2015 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import logging @@ -127,3 +115,5 @@ class ConfigFile(ConfigSource, dict): prefix -- prefix of the key """ return len([key for key in self if key.startswith(prefix)]) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/config_namespace.py b/cloudinit/sources/helpers/vmware/imc/config_namespace.py index b28830f5..2f29edd4 100644 --- a/cloudinit/sources/helpers/vmware/imc/config_namespace.py +++ b/cloudinit/sources/helpers/vmware/imc/config_namespace.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Canonical Ltd. -# Copyright (C) 2015 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2015 Canonical Ltd. +# Copyright (C) 2015 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from .config_source import ConfigSource @@ -23,3 +11,5 @@ from .config_source import ConfigSource class ConfigNamespace(ConfigSource): """Specifies the Config Namespace.""" pass + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/config_nic.py b/cloudinit/sources/helpers/vmware/imc/config_nic.py index 511cc918..d5a7c346 100644 --- a/cloudinit/sources/helpers/vmware/imc/config_nic.py +++ b/cloudinit/sources/helpers/vmware/imc/config_nic.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Canonical Ltd. -# Copyright (C) 2016 VMware INC. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2015 Canonical Ltd. +# Copyright (C) 2016 VMware INC. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import logging import os @@ -245,3 +233,5 @@ class NicConfigurator(object): fp.write('%s\n' % line) self.if_down_up() + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/config_source.py b/cloudinit/sources/helpers/vmware/imc/config_source.py index 28ef306a..2f8ea546 100644 --- a/cloudinit/sources/helpers/vmware/imc/config_source.py +++ b/cloudinit/sources/helpers/vmware/imc/config_source.py @@ -1,23 +1,13 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Canonical Ltd. -# Copyright (C) 2015 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2015 Canonical Ltd. +# Copyright (C) 2015 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. class ConfigSource(object): """Specifies a source for the Config Content.""" pass + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/guestcust_error.py b/cloudinit/sources/helpers/vmware/imc/guestcust_error.py index d1546852..db5a00dc 100644 --- a/cloudinit/sources/helpers/vmware/imc/guestcust_error.py +++ b/cloudinit/sources/helpers/vmware/imc/guestcust_error.py @@ -1,24 +1,14 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2016 Canonical Ltd. -# Copyright (C) 2016 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2016 Canonical Ltd. +# Copyright (C) 2016 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. class GuestCustErrorEnum(object): """Specifies different errors of Guest Customization engine""" GUESTCUST_ERROR_SUCCESS = 0 + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/guestcust_event.py b/cloudinit/sources/helpers/vmware/imc/guestcust_event.py index ce90c898..e84c1cb0 100644 --- a/cloudinit/sources/helpers/vmware/imc/guestcust_event.py +++ b/cloudinit/sources/helpers/vmware/imc/guestcust_event.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2016 Canonical Ltd. -# Copyright (C) 2016 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2016 Canonical Ltd. +# Copyright (C) 2016 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. class GuestCustEventEnum(object): @@ -25,3 +13,5 @@ class GuestCustEventEnum(object): GUESTCUST_EVENT_NETWORK_SETUP_FAILED = 101 GUESTCUST_EVENT_ENABLE_NICS = 103 GUESTCUST_EVENT_QUERY_NICS = 104 + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/guestcust_state.py b/cloudinit/sources/helpers/vmware/imc/guestcust_state.py index 422a096d..a8211dea 100644 --- a/cloudinit/sources/helpers/vmware/imc/guestcust_state.py +++ b/cloudinit/sources/helpers/vmware/imc/guestcust_state.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2016 Canonical Ltd. -# Copyright (C) 2016 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2016 Canonical Ltd. +# Copyright (C) 2016 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. class GuestCustStateEnum(object): @@ -23,3 +11,5 @@ class GuestCustStateEnum(object): GUESTCUST_STATE_RUNNING = 4 GUESTCUST_STATE_DONE = 5 + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/guestcust_util.py b/cloudinit/sources/helpers/vmware/imc/guestcust_util.py index c07c5949..1ab6bd41 100644 --- a/cloudinit/sources/helpers/vmware/imc/guestcust_util.py +++ b/cloudinit/sources/helpers/vmware/imc/guestcust_util.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2016 Canonical Ltd. -# Copyright (C) 2016 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2016 Canonical Ltd. +# Copyright (C) 2016 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import logging import os @@ -126,3 +114,5 @@ def enable_nics(nics): logger.warning("Can't connect network interfaces after %d attempts", enableNicsWaitRetries) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/ipv4_mode.py b/cloudinit/sources/helpers/vmware/imc/ipv4_mode.py index 873ddc3b..d793bdeb 100644 --- a/cloudinit/sources/helpers/vmware/imc/ipv4_mode.py +++ b/cloudinit/sources/helpers/vmware/imc/ipv4_mode.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Canonical Ltd. -# Copyright (C) 2015 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2015 Canonical Ltd. +# Copyright (C) 2015 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. class Ipv4ModeEnum(object): @@ -43,3 +31,5 @@ class Ipv4ModeEnum(object): # IPv4 settings should be left untouched. Reserved for future use IPV4_MODE_AS_IS = 'AS_IS' + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/nic.py b/cloudinit/sources/helpers/vmware/imc/nic.py index b5d704ea..ef8f87f7 100644 --- a/cloudinit/sources/helpers/vmware/imc/nic.py +++ b/cloudinit/sources/helpers/vmware/imc/nic.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Canonical Ltd. -# Copyright (C) 2015 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2015 Canonical Ltd. +# Copyright (C) 2015 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from .boot_proto import BootProtoEnum from .nic_base import NicBase, StaticIpv4Base, StaticIpv6Base @@ -145,3 +133,5 @@ class StaticIpv6Addr(StaticIpv6Base): @property def gateway(self): return self._nic._get('IPv6GATEWAY|' + str(self._index)) + +# vi: ts=4 expandtab diff --git a/cloudinit/sources/helpers/vmware/imc/nic_base.py b/cloudinit/sources/helpers/vmware/imc/nic_base.py index 3c892db0..de7b866d 100644 --- a/cloudinit/sources/helpers/vmware/imc/nic_base.py +++ b/cloudinit/sources/helpers/vmware/imc/nic_base.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Canonical Ltd. -# Copyright (C) 2015 VMware Inc. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2015 Canonical Ltd. +# Copyright (C) 2015 VMware Inc. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. class NicBase(object): @@ -152,3 +140,5 @@ class StaticIpv6Base(object): @return (str): the IPv6GATEWAY setting """ raise NotImplementedError('Ipv6 GATEWAY') + +# vi: ts=4 expandtab diff --git a/cloudinit/ssh_util.py b/cloudinit/ssh_util.py index c74a7ae2..be8a49e8 100644 --- a/cloudinit/ssh_util.py +++ b/cloudinit/ssh_util.py @@ -1,23 +1,10 @@ -#!/usr/bin/python -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Hafliger <juerg.haefliger@hp.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Hafliger <juerg.haefliger@hp.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import os import pwd @@ -30,15 +17,25 @@ LOG = logging.getLogger(__name__) # See: man sshd_config DEF_SSHD_CFG = "/etc/ssh/sshd_config" -# taken from openssh source key.c/key_type_from_name +# taken from openssh source openssh-7.3p1/sshkey.c: +# static const struct keytype keytypes[] = { ... } VALID_KEY_TYPES = ( - "rsa", "dsa", "ssh-rsa", "ssh-dss", "ecdsa", - "ssh-rsa-cert-v00@openssh.com", "ssh-dss-cert-v00@openssh.com", - "ssh-rsa-cert-v00@openssh.com", "ssh-dss-cert-v00@openssh.com", - "ssh-rsa-cert-v01@openssh.com", "ssh-dss-cert-v01@openssh.com", + "dsa", + "ecdsa", "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ecdsa-sha2-nistp384-cert-v01@openssh.com", - "ecdsa-sha2-nistp521-cert-v01@openssh.com") + "ecdsa-sha2-nistp521-cert-v01@openssh.com", + "ed25519", + "rsa", + "rsa-sha2-256", + "rsa-sha2-512", + "ssh-dss", + "ssh-dss-cert-v01@openssh.com", + "ssh-ed25519", + "ssh-ed25519-cert-v01@openssh.com", + "ssh-rsa", + "ssh-rsa-cert-v01@openssh.com", +) class AuthKeyLine(object): @@ -312,3 +309,5 @@ def parse_ssh_config_map(fname): continue ret[line.key] = line.value return ret + +# vi: ts=4 expandtab diff --git a/cloudinit/stages.py b/cloudinit/stages.py index 86a13785..b0552dde 100644 --- a/cloudinit/stages.py +++ b/cloudinit/stages.py @@ -1,24 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import copy import os @@ -845,23 +829,15 @@ class Modules(object): def fetch_base_config(): - base_cfgs = [] - default_cfg = util.get_builtin_cfg() - - # Anything in your conf.d location?? - # or the 'default' cloud.cfg location??? - base_cfgs.append(util.read_conf_with_confd(CLOUD_CONFIG)) - - # Kernel/cmdline parameters override system config - kern_contents = util.read_cc_from_cmdline() - if kern_contents: - base_cfgs.append(util.load_yaml(kern_contents, default={})) - - # And finally the default gets to play - if default_cfg: - base_cfgs.append(default_cfg) - - return util.mergemanydict(base_cfgs) + return util.mergemanydict( + [ + # builtin config + util.get_builtin_cfg(), + # Anything in your conf.d or 'default' cloud.cfg location. + util.read_conf_with_confd(CLOUD_CONFIG), + # Kernel/cmdline parameters override system config + util.read_conf_from_cmdline(), + ], reverse=True) def _pkl_store(obj, fname): @@ -895,3 +871,5 @@ def _pkl_load(fname): except Exception: util.logexc(LOG, "Failed loading pickled blob from %s", fname) return None + +# vi: ts=4 expandtab diff --git a/cloudinit/templater.py b/cloudinit/templater.py index 41ef27e3..648cd218 100644 --- a/cloudinit/templater.py +++ b/cloudinit/templater.py @@ -1,26 +1,14 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# Copyright (C) 2016 Amazon.com, Inc. or its affiliates. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# Author: Andrew Jorgensen <ajorgens@amazon.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. +# Copyright (C) 2016 Amazon.com, Inc. or its affiliates. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Author: Andrew Jorgensen <ajorgens@amazon.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import collections import re @@ -153,3 +141,5 @@ def render_string(content, params): params = {} template_type, renderer, content = detect_template(content) return renderer(content, params) + +# vi: ts=4 expandtab diff --git a/cloudinit/type_utils.py b/cloudinit/type_utils.py index b93efd6a..6132654b 100644 --- a/cloudinit/type_utils.py +++ b/cloudinit/type_utils.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import types @@ -50,3 +38,5 @@ def obj_name(obj): return repr(obj) else: return obj_name(obj.__class__) + +# vi: ts=4 expandtab diff --git a/cloudinit/url_helper.py b/cloudinit/url_helper.py index c05e9d90..312b0460 100644 --- a/cloudinit/url_helper.py +++ b/cloudinit/url_helper.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import json import os @@ -507,3 +495,5 @@ def oauth_headers(url, consumer_key, token_key, token_secret, consumer_secret, timestamp=timestamp) uri, signed_headers, body = client.sign(url) return signed_headers + +# vi: ts=4 expandtab diff --git a/cloudinit/user_data.py b/cloudinit/user_data.py index 393bf0bb..cfe5aa2f 100644 --- a/cloudinit/user_data.py +++ b/cloudinit/user_data.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import os @@ -354,3 +342,5 @@ def convert_string(raw_data, content_type=NOT_MULTIPART_TYPE): msg = create_binmsg(raw_data, content_type) return msg + +# vi: ts=4 expandtab diff --git a/cloudinit/util.py b/cloudinit/util.py index ed2d93e5..5725129e 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Canonical Ltd. -# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Scott Moser <scott.moser@canonical.com> -# Author: Juerg Haefliger <juerg.haefliger@hp.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Canonical Ltd. +# Copyright (C) 2012, 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import contextlib import copy as obj_copy @@ -235,15 +223,16 @@ class ProcessExecutionError(IOError): 'Command: %(cmd)s\n' 'Exit code: %(exit_code)s\n' 'Reason: %(reason)s\n' - 'Stdout: %(stdout)r\n' - 'Stderr: %(stderr)r') + 'Stdout: %(stdout)s\n' + 'Stderr: %(stderr)s') + empty_attr = '-' def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None, description=None, reason=None, errno=None): if not cmd: - self.cmd = '-' + self.cmd = self.empty_attr else: self.cmd = cmd @@ -253,36 +242,56 @@ class ProcessExecutionError(IOError): self.description = description if not isinstance(exit_code, six.integer_types): - self.exit_code = '-' + self.exit_code = self.empty_attr else: self.exit_code = exit_code if not stderr: - self.stderr = '' + self.stderr = self.empty_attr else: - self.stderr = stderr + self.stderr = self._indent_text(stderr) if not stdout: - self.stdout = '' + self.stdout = self.empty_attr else: - self.stdout = stdout + self.stdout = self._indent_text(stdout) if reason: self.reason = reason else: - self.reason = '-' + self.reason = self.empty_attr self.errno = errno message = self.MESSAGE_TMPL % { - 'description': self.description, - 'cmd': self.cmd, - 'exit_code': self.exit_code, - 'stdout': self.stdout, - 'stderr': self.stderr, - 'reason': self.reason, + 'description': self._ensure_string(self.description), + 'cmd': self._ensure_string(self.cmd), + 'exit_code': self._ensure_string(self.exit_code), + 'stdout': self._ensure_string(self.stdout), + 'stderr': self._ensure_string(self.stderr), + 'reason': self._ensure_string(self.reason), } IOError.__init__(self, message) + def _ensure_string(self, text): + """ + if data is bytes object, decode + """ + return text.decode() if isinstance(text, six.binary_type) else text + + def _indent_text(self, text, indent_level=8): + """ + indent text on all but the first line, allowing for easy to read output + """ + cr = '\n' + indent = ' ' * indent_level + # if input is bytes, return bytes + if isinstance(text, six.binary_type): + cr = cr.encode() + indent = indent.encode() + # remove any newlines at end of text first to prevent unneeded blank + # line in output + return text.rstrip(cr).replace(cr, cr + indent) + class SeLinuxGuard(object): def __init__(self, path, recursive=False): @@ -972,6 +981,11 @@ def read_conf_with_confd(cfgfile): return mergemanydict([confd_cfg, cfg]) +def read_conf_from_cmdline(cmdline=None): + # return a dictionary or config on the cmdline or None + return load_yaml(read_cc_from_cmdline(cmdline=cmdline)) + + def read_cc_from_cmdline(cmdline=None): # this should support reading cloud-config information from # the kernel command line. It is intended to support content of the @@ -2387,3 +2401,5 @@ def system_is_snappy(): if os.path.isdir("/etc/system-image/config.d/"): return True return False + +# vi: ts=4 expandtab diff --git a/cloudinit/version.py b/cloudinit/version.py index 5d4975cf..92bace1a 100644 --- a/cloudinit/version.py +++ b/cloudinit/version.py @@ -1,23 +1,13 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. -__VERSION__ = "0.7.8" +__VERSION__ = "0.7.9" def version_string(): return __VERSION__ + +# vi: ts=4 expandtab diff --git a/config/cloud.cfg.d/05_logging.cfg b/config/cloud.cfg.d/05_logging.cfg index 2e180730..937b07f8 100644 --- a/config/cloud.cfg.d/05_logging.cfg +++ b/config/cloud.cfg.d/05_logging.cfg @@ -53,14 +53,19 @@ _log: args=("/dev/log", handlers.SysLogHandler.LOG_USER) log_cfgs: -# These will be joined into a string that defines the configuration - - [ *log_base, *log_syslog ] -# These will be joined into a string that defines the configuration +# Array entries in this list will be joined into a string +# that defines the configuration. +# +# If you want logs to go to syslog, uncomment the following line. +# - [ *log_base, *log_syslog ] +# +# The default behavior is to just log to a file. +# This mechanism that does not depend on a system service to operate. - [ *log_base, *log_file ] -# A file path can also be used +# A file path can also be used. # - /etc/log.conf -# this tells cloud-init to redirect its stdout and stderr to +# This tells cloud-init to redirect its stdout and stderr to # 'tee -a /var/log/cloud-init-output.log' so the user can see output # there without needing to look on the console. output: {all: '| tee -a /var/log/cloud-init-output.log'} diff --git a/doc/examples/cloud-config-apt.txt b/doc/examples/cloud-config-apt.txt index 1a0fc6f2..ff8206f6 100644 --- a/doc/examples/cloud-config-apt.txt +++ b/doc/examples/cloud-config-apt.txt @@ -70,7 +70,7 @@ apt: # modifications have been made. # Suites are even disabled if no other modification was made, # but not if is preserve_sources_list is active. - # There is a special alias “$RELEASE” as in the sources that will be replace + # There is a special alias "$RELEASE" as in the sources that will be replace # by the matching release. # # To ease configuration and improve readability the following common ubuntu @@ -84,7 +84,7 @@ apt: # There is no harm in specifying a suite to be disabled that is not found in # the source.list file (just a no-op then) # - # Note: Lines don’t get deleted, but disabled by being converted to a comment. + # Note: Lines don't get deleted, but disabled by being converted to a comment. # The following example disables all usual defaults except $RELEASE-security. # On top it disables a custom suite called "mysuite" disable_suites: [$RELEASE-updates, backports, $RELEASE, mysuite] diff --git a/doc/examples/cloud-config-boot-cmds.txt b/doc/examples/cloud-config-boot-cmds.txt index 5c05bef7..84e487a5 100644 --- a/doc/examples/cloud-config-boot-cmds.txt +++ b/doc/examples/cloud-config-boot-cmds.txt @@ -9,7 +9,7 @@ # boothook, but possibly with more friendly. # - bootcmd will run on every boot # - the INSTANCE_ID variable will be set to the current instance id. -# - you can use 'cloud-init-boot-per' command to help only run once +# - you can use 'cloud-init-per' command to help only run once bootcmd: - echo 192.168.1.130 us.archive.ubuntu.com >> /etc/hosts - [ cloud-init-per, once, mymkfs, mkfs, /dev/vdb ] diff --git a/doc/examples/cloud-config-gluster.txt b/doc/examples/cloud-config-gluster.txt index f8183e77..cb979123 100644 --- a/doc/examples/cloud-config-gluster.txt +++ b/doc/examples/cloud-config-gluster.txt @@ -1,6 +1,6 @@ #cloud-config # vim: syntax=yaml -# Mounts volfile exported by glusterfsd running on +# Mounts volfile exported by glusterfsd running on # "volfile-server-hostname" onto the local mount point '/mnt/data' # # In reality, replace 'volfile-server-hostname' with one of your nodes @@ -10,7 +10,7 @@ packages: - glusterfs-client mounts: - - [ 'volfile-server-hostname:6996', /mnt/data, glusterfs, "defaults,nobootwait", "0", "2" ] + - [ 'volfile-server-hostname:6996', /mnt/data, glusterfs, "defaults,nofail", "0", "2" ] runcmd: - [ modprobe, fuse ] diff --git a/doc/examples/cloud-config-mount-points.txt b/doc/examples/cloud-config-mount-points.txt index aa676c24..5a6c24f5 100644 --- a/doc/examples/cloud-config-mount-points.txt +++ b/doc/examples/cloud-config-mount-points.txt @@ -23,19 +23,19 @@ # - if an entry does not have all 6 fields, they will be filled in # with values from 'mount_default_fields' below. # -# Note, that you should set 'nobootwait' (see man fstab) for volumes that may -# not be attached at instance boot (or reboot) +# Note, that you should set 'nofail' (see man fstab) for volumes that may not +# be attached at instance boot (or reboot). # mounts: - [ ephemeral0, /mnt, auto, "defaults,noexec" ] - [ sdc, /opt/data ] - - [ xvdh, /opt/data, "auto", "defaults,nobootwait", "0", "0" ] + - [ xvdh, /opt/data, "auto", "defaults,nofail", "0", "0" ] - [ dd, /dev/zero ] # mount_default_fields # These values are used to fill in any entries in 'mounts' that are not # complete. This must be an array, and must have 7 fields. -mount_default_fields: [ None, None, "auto", "defaults,nobootwait", "0", "2" ] +mount_default_fields: [ None, None, "auto", "defaults,nofail", "0", "2" ] # swap can also be set up by the 'mounts' module diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt index 190029e4..c5f84b13 100644 --- a/doc/examples/cloud-config.txt +++ b/doc/examples/cloud-config.txt @@ -46,19 +46,19 @@ packages: # - if an entry does not have all 6 fields, they will be filled in # with values from 'mount_default_fields' below. # -# Note, that you should set 'nobootwait' (see man fstab) for volumes that may +# Note, that you should set 'nofail' (see man fstab) for volumes that may # not be attached at instance boot (or reboot) # mounts: - [ ephemeral0, /mnt, auto, "defaults,noexec" ] - [ sdc, /opt/data ] - - [ xvdh, /opt/data, "auto", "defaults,nobootwait", "0", "0" ] + - [ xvdh, /opt/data, "auto", "defaults,nofail", "0", "0" ] - [ dd, /dev/zero ] # mount_default_fields # These values are used to fill in any entries in 'mounts' that are not # complete. This must be an array, and must have 7 fields. -mount_default_fields: [ None, None, "auto", "defaults,nobootwait", "0", "2" ] +mount_default_fields: [ None, None, "auto", "defaults,nofail", "0", "2" ] # add each entry to ~/.ssh/authorized_keys for the configured user or the # first user defined in the user definition directive. diff --git a/doc/rtd/index.rst b/doc/rtd/index.rst index 3caf33f3..8f163b6a 100644 --- a/doc/rtd/index.rst +++ b/doc/rtd/index.rst @@ -41,6 +41,7 @@ initialization of a cloud instance. topics/vendordata.rst topics/moreinfo.rst topics/hacking.rst + topics/tests.rst .. _Cloud-init: https://launchpad.net/cloud-init .. vi: textwidth=78 diff --git a/doc/rtd/topics/boot.rst b/doc/rtd/topics/boot.rst index 9d42336c..859409a6 100644 --- a/doc/rtd/topics/boot.rst +++ b/doc/rtd/topics/boot.rst @@ -21,7 +21,7 @@ boot goals. By default, this generator will enable cloud-init. It will not enable cloud-init if either: * A file exists: ``/etc/cloud/cloud-init.disabled`` - * The kernel command line as fond in /proc/cmdline contains ``cloud-init=disabled``. + * The kernel command line as found in /proc/cmdline contains ``cloud-init=disabled``. When running in a container, the kernel command line is not honored, but cloud-init will read an environment variable named ``KERNEL_CMDLINE`` in its place. @@ -56,7 +56,7 @@ is rendered. This includes clearing of all previous (stale) configuration including persistent device naming with old mac addresses. This stage must block network bring-up or any stale configuration might -already have been applied. That could have negative effects such as DCHP +already have been applied. That could have negative effects such as DHCP hooks or broadcast of an old hostname. It would also put the system in an odd state to recover from as it may then have to restart network devices. diff --git a/doc/rtd/topics/format.rst b/doc/rtd/topics/format.rst index 5898d17a..ed87d3ed 100644 --- a/doc/rtd/topics/format.rst +++ b/doc/rtd/topics/format.rst @@ -9,7 +9,7 @@ Gzip Compressed Content Content found to be gzip compressed will be uncompressed. The uncompressed data will then be used as if it were not compressed. -This is typically is useful because user-data is limited to ~16384 [#]_ bytes. +This is typically useful because user-data is limited to ~16384 [#]_ bytes. Mime Multi Part Archive ======================= diff --git a/doc/rtd/topics/logging.rst b/doc/rtd/topics/logging.rst index c6afca16..4fd7e28e 100644 --- a/doc/rtd/topics/logging.rst +++ b/doc/rtd/topics/logging.rst @@ -22,7 +22,7 @@ output to ``tee``, or ``logger``. If only a filename is provided, cloud-init will append its output to the file as though ``>>`` was specified. By default, cloud-init loads its output configuration from -``/etc/cloud/coud.cfg.d/05_logging.cfg``. The default config directs both +``/etc/cloud/cloud.cfg.d/05_logging.cfg``. The default config directs both stdout and stderr from all cloud-init stages to ``/var/log/cloud-init-output.log``. The default config is given as :: diff --git a/doc/rtd/topics/tests.rst b/doc/rtd/topics/tests.rst new file mode 100644 index 00000000..00c63c63 --- /dev/null +++ b/doc/rtd/topics/tests.rst @@ -0,0 +1,275 @@ +**************** +Test Development +**************** + + +Overview +======== + +The purpose of this page is to describe how to write integration tests for +cloud-init. As a test writer you need to develop a test configuration and +a verification file: + + * The test configuration specifies a specific cloud-config to be used by + cloud-init and a list of arbitrary commands to capture the output of + (e.g my_test.yaml) + + * The verification file runs tests on the collected output to determine + the result of the test (e.g. my_test.py) + +The names must match, however the extensions will of course be different, +yaml vs py. + +Configuration +============= + +The test configuration is a YAML file such as *ntp_server.yaml* below: + +.. code-block:: yaml + + # + # NTP config using specific servers (ntp_server.yaml) + # + cloud_config: | + #cloud-config + ntp: + servers: + - pool.ntp.org + collect_scripts: + ntp_installed_servers: | + #!/bin/bash + dpkg -l | grep ntp | wc -l + ntp_conf_dist_servers: | + #!/bin/bash + ls /etc/ntp.conf.dist | wc -l + ntp_conf_servers: | + #!/bin/bash + cat /etc/ntp.conf | grep '^server' + + +There are two keys, 1 required and 1 optional, in the YAML file: + +1. The required key is ``cloud_config``. This should be a string of valid + YAML that is exactly what would normally be placed in a cloud-config file, + including the cloud-config header. This essentially sets up the scenario + under test. + +2. The optional key is ``collect_scripts``. This key has one or more + sub-keys containing strings of arbitrary commands to execute (e.g. + ```cat /var/log/cloud-config-output.log```). In the example above the + output of dpkg is captured, grep for ntp, and the number of lines + reported. The name of the sub-key is important. The sub-key is used by + the verification script to recall the output of the commands ran. + +Default Collect Scripts +----------------------- + +By default the following files will be collected for every test. There is +no need to specify these items: + +* ``/var/log/cloud-init.log`` +* ``/var/log/cloud-init-output.log`` +* ``/run/cloud-init/.instance-id`` +* ``/run/cloud-init/result.json`` +* ``/run/cloud-init/status.json`` +* ```dpkg-query -W -f='${Version}' cloud-init``` + +Verification +============ + +The verification script is a Python file with unit tests like the one, +`ntp_server.py`, below: + +.. code-block:: python + + """cloud-init Integration Test Verify Script (ntp_server.yaml)""" + from tests.cloud_tests.testcases import base + + + class TestNtpServers(base.CloudTestCase): + """Test ntp module""" + + def test_ntp_installed(self): + """Test ntp installed""" + out = self.get_data_file('ntp_installed_servers') + self.assertEqual(1, int(out)) + + def test_ntp_dist_entries(self): + """Test dist config file has one entry""" + out = self.get_data_file('ntp_conf_dist_servers') + self.assertEqual(1, int(out)) + + def test_ntp_entires(self): + """Test config entries""" + out = self.get_data_file('ntp_conf_servers') + self.assertIn('server pool.ntp.org iburst', out) + + +Here is a breakdown of the unit test file: + +* The import statement allows access to the output files. + +* The class can be named anything, but must import the ``base.CloudTestCase`` + +* There can be 1 to N number of functions with any name, however only + tests starting with ``test_*`` will be executed. + +* Output from the commands can be accessed via + ``self.get_data_file('key')`` where key is the sub-key of + ``collect_scripts`` above. + +Layout +====== + +Integration tests are located under the `tests/cloud_tests` directory. +Test configurations are placed under `configs` and the test verification +scripts under `testcases`: + +.. code-block:: bash + + cloud-init$ tree -d tests/cloud_tests/ + tests/cloud_tests/ + ├── configs + │ ├── bugs + │ ├── examples + │ ├── main + │ └── modules + └── testcases + ├── bugs + ├── examples + ├── main + └── modules + +The sub-folders of bugs, examples, main, and modules help organize the +tests. View the README.md in each to understand in more detail each +directory. + + +Development Checklist +===================== + +* Configuration File + * Named 'your_test_here.yaml' + * Contains at least a valid cloud-config + * Optionally, commands to capture additional output + * Valid YAML + * Placed in the appropriate sub-folder in the configs directory +* Verification File + * Named 'your_test_here.py' + * Valid unit tests validating output collected + * Passes pylint & pep8 checks + * Placed in the appropriate sub-folder in the testcsaes directory +* Tested by running the test: + + .. code-block:: bash + + $ python3 -m tests.cloud_tests run -v -n <release of choice> \ + --deb <build of cloud-init> \ + -t tests/cloud_tests/configs/<dir>/your_test_here.yaml + + +Execution +========= + +Executing tests has three options: + +* ``run`` an alias to run both ``collect`` and ``verify`` + +* ``collect`` deploys on the specified platform and os, patches with the + requested deb or rpm, and finally collects output of the arbitrary + commands. + +* ``verify`` given a directory of test data, run the Python unit tests on + it to generate results. + +Run +--- +The first example will provide a complete end-to-end run of data +collection and verification. There are additional examples below +explaining how to run one or the other independently. + +.. code-block:: bash + + $ git clone https://git.launchpad.net/cloud-init + $ cd cloud-init + $ python3 -m tests.cloud_tests run -v -n trusty -n xenial \ + --deb cloud-init_0.7.8~my_patch_all.deb + +The above command will do the following: + +* ``-v`` verbose output + +* ``run`` both collect output and run tests the output + +* ``-n trusty`` on the Ubuntu Trusty release + +* ``-n xenial`` on the Ubuntu Xenial release + +* ``--deb cloud-init_0.7.8~patch_all.deb`` use this deb as the version of + cloud-init to run with + +For a more detailed explanation of each option see below. + +Collect +------- + +If developing tests it may be necessary to see if cloud-config works as +expected and the correct files are pulled down. In this case only a +collect can be ran by running: + +.. code-block:: bash + + $ python3 -m tests.cloud_tests collect -n xenial -d /tmp/collection \ + --deb cloud-init_0.7.8~my_patch_all.deb + +The above command will run the collection tests on xenial with the +provided deb and place all results into `/tmp/collection`. + +Verify +------ + +When developing tests it is much easier to simply rerun the verify scripts +without the more lengthy collect process. This can be done by running: + +.. code-block:: bash + + $ python3 -m tests.cloud_tests verify -d /tmp/collection + +The above command will run the verify scripts on the data discovered in +`/tmp/collection`. + + +Architecture +============ + +The following outlines the process flow during a complete end-to-end LXD-backed test. + +1. Configuration + * The back end and specific OS releases are verified as supported + * The test or tests that need to be run are determined either by directory or by individual yaml + +2. Image Creation + * Acquire the daily LXD image + * Install the specified cloud-init package + * Clean the image so that it does not appear to have been booted + * A snapshot of the image is created and reused by all tests + +3. Configuration + * For each test, the cloud-config is injected into a copy of the + snapshot and booted + * The framework waits for ``/var/lib/cloud/instance/boot-finished`` + (up to 120 seconds) + * All default commands are ran and output collected + * Any commands the user specified are executed and output collected + +4. Verification + * The default commands are checked for any failures, errors, and + warnings to validate basic functionality of cloud-init completed + successfully + * The user generated unit tests are then ran validating against the + collected output + +5. Results + * If any failures were detected the test suite returns a failure + + diff --git a/packages/debian/copyright b/packages/debian/copyright index c694f30d..c9c7d231 100644 --- a/packages/debian/copyright +++ b/packages/debian/copyright @@ -12,6 +12,7 @@ Upstream Author: Scott Moser <smoser@canonical.com> Chuck Short <chuck.short@canonical.com> 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 @@ -27,3 +28,18 @@ License: GPL-3 The complete text of the GPL version 3 can be seen in /usr/share/common-licenses/GPL-3. +License: Apache-2.0 + 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/redhat/cloud-init.spec.in b/packages/redhat/cloud-init.spec.in index d0ae048f..fd3cf938 100644 --- a/packages/redhat/cloud-init.spec.in +++ b/packages/redhat/cloud-init.spec.in @@ -11,7 +11,7 @@ Release: 1${subrelease}%{?dist} Summary: Cloud instance init scripts Group: System Environment/Base -License: GPLv3 +License: Dual-licesed GPLv3 or Apache 2.0 URL: http://launchpad.net/cloud-init Source0: ${archive_name} @@ -171,10 +171,11 @@ fi %{_unitdir}/cloud-* #end if +%{_sysconfdir}/NetworkManager/dispatcher.d/hook-network-manager +%{_sysconfdir}/dhcp/dhclient-exit-hooks.d/hook-dhclient + # Program binaries %{_bindir}/cloud-init* -%{_libexecdir}/%{name}/uncloud-init -%{_libexecdir}/%{name}/write-ssh-key-fingerprints # Docs %doc LICENSE ChangeLog TODO.rst requirements.txt diff --git a/packages/suse/cloud-init.spec.in b/packages/suse/cloud-init.spec.in index f994a0cf..6ce0be8c 100644 --- a/packages/suse/cloud-init.spec.in +++ b/packages/suse/cloud-init.spec.in @@ -10,7 +10,7 @@ Release: 1${subrelease}%{?dist} Summary: Cloud instance init scripts Group: System/Management -License: GPLv3 +License: Dual licensed GPLv3 or Apache 2.0 URL: http://launchpad.net/cloud-init Source0: ${archive_name} @@ -1,24 +1,12 @@ -# vi: ts=4 expandtab -# -# Distutils magic for ec2-init -# -# Copyright (C) 2009 Canonical Ltd. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Soren Hansen <soren@canonical.com> -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2009 Canonical Ltd. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Soren Hansen <soren@canonical.com> +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. + +# Distutils magic for ec2-init from glob import glob @@ -209,7 +197,7 @@ setuptools.setup( url='http://launchpad.net/cloud-init/', packages=setuptools.find_packages(exclude=['tests']), scripts=['tools/cloud-init-per'], - license='GPLv3', + license='Dual-licensed under GPLv3 or Apache 2.0', data_files=data_files, install_requires=requirements, cmdclass=cmdclass, @@ -219,3 +207,5 @@ setuptools.setup( ], } ) + +# vi: ts=4 expandtab diff --git a/sysvinit/redhat/cloud-config b/sysvinit/redhat/cloud-config index ad8ed831..6da8250c 100755 --- a/sysvinit/redhat/cloud-config +++ b/sysvinit/redhat/cloud-config @@ -1,22 +1,9 @@ #!/bin/sh - -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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. +# Copyright (C) 2012 Yahoo! Inc. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # +# This file is part of cloud-init. See LICENSE file for license information. # See: http://wiki.debian.org/LSBInitScripts # See: http://tiny.cc/czvbgw diff --git a/sysvinit/redhat/cloud-final b/sysvinit/redhat/cloud-final index aeae8903..8d6f7dfa 100755 --- a/sysvinit/redhat/cloud-final +++ b/sysvinit/redhat/cloud-final @@ -1,22 +1,9 @@ #!/bin/sh - -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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. +# Copyright (C) 2012 Yahoo! Inc. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # +# This file is part of cloud-init. See LICENSE file for license information. # See: http://wiki.debian.org/LSBInitScripts # See: http://tiny.cc/czvbgw diff --git a/sysvinit/redhat/cloud-init b/sysvinit/redhat/cloud-init index c1c92ad0..f14aca24 100755 --- a/sysvinit/redhat/cloud-init +++ b/sysvinit/redhat/cloud-init @@ -1,22 +1,9 @@ #!/bin/sh - -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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. +# Copyright (C) 2012 Yahoo! Inc. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # +# This file is part of cloud-init. See LICENSE file for license information. # See: http://wiki.debian.org/LSBInitScripts # See: http://tiny.cc/czvbgw diff --git a/sysvinit/redhat/cloud-init-local b/sysvinit/redhat/cloud-init-local index b9caedbd..5788fcb1 100755 --- a/sysvinit/redhat/cloud-init-local +++ b/sysvinit/redhat/cloud-init-local @@ -1,22 +1,9 @@ #!/bin/sh - -# -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> -# -# 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. +# Copyright (C) 2012 Yahoo! Inc. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # +# This file is part of cloud-init. See LICENSE file for license information. # See: http://wiki.debian.org/LSBInitScripts # See: http://tiny.cc/czvbgw diff --git a/tests/cloud_tests/__init__.py b/tests/cloud_tests/__init__.py new file mode 100644 index 00000000..099c357f --- /dev/null +++ b/tests/cloud_tests/__init__.py @@ -0,0 +1,31 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +import logging +import os + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +TESTCASES_DIR = os.path.join(BASE_DIR, 'testcases') +TEST_CONF_DIR = os.path.join(BASE_DIR, 'configs') + + +def _initialize_logging(): + """ + configure logging for cloud_tests + """ + logger = logging.getLogger(__name__) + logger.setLevel(logging.DEBUG) + formatter = logging.Formatter( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s') + + console = logging.StreamHandler() + console.setLevel(logging.DEBUG) + console.setFormatter(formatter) + + logger.addHandler(console) + + return logger + + +LOG = _initialize_logging() + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/__main__.py b/tests/cloud_tests/__main__.py new file mode 100644 index 00000000..ef7d1878 --- /dev/null +++ b/tests/cloud_tests/__main__.py @@ -0,0 +1,93 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +import argparse +import logging +import shutil +import sys +import tempfile + +from tests.cloud_tests import (args, collect, manage, verify) +from tests.cloud_tests import LOG + + +def configure_log(args): + """ + configure logging + """ + level = logging.INFO + if args.verbose: + level = logging.DEBUG + elif args.quiet: + level = logging.WARN + LOG.setLevel(level) + + +def run(args): + """ + run full test suite + """ + failed = 0 + args.data_dir = tempfile.mkdtemp(prefix='cloud_test_data_') + LOG.debug('using tmpdir %s', args.data_dir) + try: + failed += collect.collect(args) + failed += verify.verify(args) + except Exception: + failed += 1 + raise + finally: + # TODO: make this configurable via environ or cmdline + if failed: + LOG.warn('some tests failed, leaving data in %s', args.data_dir) + else: + shutil.rmtree(args.data_dir) + return failed + + +def main(): + """ + entry point for cloud test suite + """ + # configure parser + parser = argparse.ArgumentParser(prog='cloud_tests') + subparsers = parser.add_subparsers(dest="subcmd") + subparsers.required = True + + def add_subparser(name, description, arg_sets): + """ + add arguments to subparser + """ + subparser = subparsers.add_parser(name, help=description) + for (_args, _kwargs) in (a for arg_set in arg_sets for a in arg_set): + subparser.add_argument(*_args, **_kwargs) + + # configure subparsers + for (name, (description, arg_sets)) in args.SUBCMDS.items(): + add_subparser(name, description, + [args.ARG_SETS[arg_set] for arg_set in arg_sets]) + + # parse arguments + parsed = parser.parse_args() + + # process arguments + configure_log(parsed) + (_, arg_sets) = args.SUBCMDS[parsed.subcmd] + for normalizer in [args.NORMALIZERS[arg_set] for arg_set in arg_sets]: + parsed = normalizer(parsed) + if not parsed: + return -1 + + # run handler + LOG.debug('running with args: %s\n', parsed) + return { + 'collect': collect.collect, + 'create': manage.create, + 'run': run, + 'verify': verify.verify, + }[parsed.subcmd](parsed) + + +if __name__ == "__main__": + sys.exit(main()) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/args.py b/tests/cloud_tests/args.py new file mode 100644 index 00000000..b68cc98e --- /dev/null +++ b/tests/cloud_tests/args.py @@ -0,0 +1,221 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +import os + +from tests.cloud_tests import config, util +from tests.cloud_tests import LOG + +ARG_SETS = { + 'COLLECT': ( + (('-p', '--platform'), + {'help': 'platform(s) to run tests on', 'metavar': 'PLATFORM', + 'action': 'append', 'choices': config.list_enabled_platforms(), + 'default': []}), + (('-n', '--os-name'), + {'help': 'the name(s) of the OS(s) to test', 'metavar': 'NAME', + 'action': 'append', 'choices': config.list_enabled_distros(), + 'default': []}), + (('-t', '--test-config'), + {'help': 'test config file(s) to use', 'metavar': 'FILE', + 'action': 'append', 'default': []}),), + 'CREATE': ( + (('-c', '--config'), + {'help': 'cloud-config yaml for testcase', 'metavar': 'DATA', + 'action': 'store', 'required': False, 'default': None}), + (('-e', '--enable'), + {'help': 'enable testcase', 'required': False, 'default': False, + 'action': 'store_true'}), + (('name',), + {'help': 'testcase name, in format "<category>/<test>"', + 'action': 'store'}), + (('-d', '--description'), + {'help': 'description of testcase', 'required': False}), + (('-f', '--force'), + {'help': 'overwrite already existing test', 'required': False, + 'action': 'store_true', 'default': False}),), + 'INTERFACE': ( + (('-v', '--verbose'), + {'help': 'verbose output', 'action': 'store_true', 'default': False}), + (('-q', '--quiet'), + {'help': 'quiet output', 'action': 'store_true', 'default': False}),), + 'OUTPUT': ( + (('-d', '--data-dir'), + {'help': 'directory to store test data in', + 'action': 'store', 'metavar': 'DIR', 'required': True}),), + 'RESULT': ( + (('-r', '--result'), + {'help': 'file to write results to', + 'action': 'store', 'metavar': 'FILE'}),), + 'SETUP': ( + (('--deb',), + {'help': 'install deb', 'metavar': 'FILE', 'action': 'store'}), + (('--rpm',), + {'help': 'install rpm', 'metavar': 'FILE', 'action': 'store'}), + (('--script',), + {'help': 'script to set up image', 'metavar': 'DATA', + 'action': 'store'}), + (('--repo',), + {'help': 'repo to enable (implies -u)', 'metavar': 'NAME', + 'action': 'store'}), + (('--ppa',), + {'help': 'ppa to enable (implies -u)', 'metavar': 'NAME', + 'action': 'store'}), + (('-u', '--upgrade'), + {'help': 'upgrade before starting tests', 'action': 'store_true', + 'default': False}),), +} + +SUBCMDS = { + 'collect': ('collect test data', + ('COLLECT', 'INTERFACE', 'OUTPUT', 'RESULT', 'SETUP')), + 'create': ('create new test case', ('CREATE', 'INTERFACE')), + 'run': ('run test suite', ('COLLECT', 'INTERFACE', 'RESULT', 'SETUP')), + 'verify': ('verify test data', ('INTERFACE', 'OUTPUT', 'RESULT')), +} + + +def _empty_normalizer(args): + """ + do not normalize arguments + """ + return args + + +def normalize_create_args(args): + """ + normalize CREATE arguments + args: parsed args + return_value: updated args, or None if errors occurred + """ + # ensure valid name for new test + if len(args.name.split('/')) != 2: + LOG.error('invalid test name: %s', args.name) + return None + if os.path.exists(config.name_to_path(args.name)): + msg = 'test: {} already exists'.format(args.name) + if args.force: + LOG.warn('%s but ignoring due to --force', msg) + else: + LOG.error(msg) + return None + + # ensure test config valid if specified + if isinstance(args.config, str) and len(args.config) == 0: + LOG.error('test config cannot be empty if specified') + return None + + # ensure description valid if specified + if (isinstance(args.description, str) and + (len(args.description) > 70 or len(args.description) == 0)): + LOG.error('test description must be between 1 and 70 characters') + return None + + return args + + +def normalize_collect_args(args): + """ + normalize COLLECT arguments + args: parsed args + return_value: updated args, or None if errors occurred + """ + # platform should default to all supported + if len(args.platform) == 0: + args.platform = config.list_enabled_platforms() + args.platform = util.sorted_unique(args.platform) + + # os name should default to all enabled + # if os name is provided ensure that all provided are supported + if len(args.os_name) == 0: + args.os_name = config.list_enabled_distros() + else: + supported = config.list_enabled_distros() + invalid = [os_name for os_name in args.os_name + if os_name not in supported] + if len(invalid) != 0: + LOG.error('invalid os name(s): %s', invalid) + return None + args.os_name = util.sorted_unique(args.os_name) + + # test configs should default to all enabled + # if test configs are provided, ensure that all provided are valid + if len(args.test_config) == 0: + args.test_config = config.list_test_configs() + else: + valid = [] + invalid = [] + for name in args.test_config: + if os.path.exists(name): + valid.append(name) + elif os.path.exists(config.name_to_path(name)): + valid.append(config.name_to_path(name)) + else: + invalid.append(name) + if len(invalid) != 0: + LOG.error('invalid test config(s): %s', invalid) + return None + else: + args.test_config = valid + args.test_config = util.sorted_unique(args.test_config) + + return args + + +def normalize_output_args(args): + """ + normalize OUTPUT arguments + args: parsed args + return_value: updated args, or None if errors occurred + """ + if not args.data_dir: + LOG.error('--data-dir must be specified') + return None + + # ensure clean output dir if collect + # ensure data exists if verify + if args.subcmd == 'collect': + if not util.is_clean_writable_dir(args.data_dir): + LOG.error('data_dir must be empty/new and must be writable') + return None + elif args.subcmd == 'verify': + if not os.path.exists(args.data_dir): + LOG.error('data_dir %s does not exist', args.data_dir) + return None + + return args + + +def normalize_setup_args(args): + """ + normalize SETUP arguments + args: parsed args + return_value: updated_args, or None if errors occurred + """ + # ensure deb or rpm valid if specified + for pkg in (args.deb, args.rpm): + if pkg is not None and not os.path.exists(pkg): + LOG.error('cannot find package: %s', pkg) + return None + + # if repo or ppa to be enabled run upgrade + if args.repo or args.ppa: + args.upgrade = True + + # if ppa is specified, remove leading 'ppa:' if any + _ppa_header = 'ppa:' + if args.ppa and args.ppa.startswith(_ppa_header): + args.ppa = args.ppa[len(_ppa_header):] + + return args + + +NORMALIZERS = { + 'COLLECT': normalize_collect_args, + 'CREATE': normalize_create_args, + 'INTERFACE': _empty_normalizer, + 'OUTPUT': normalize_output_args, + 'RESULT': _empty_normalizer, + 'SETUP': normalize_setup_args, +} + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/collect.py b/tests/cloud_tests/collect.py new file mode 100644 index 00000000..68b47d7a --- /dev/null +++ b/tests/cloud_tests/collect.py @@ -0,0 +1,161 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from tests.cloud_tests import (config, LOG, setup_image, util) +from tests.cloud_tests.stage import (PlatformComponent, run_stage, run_single) +from tests.cloud_tests import (platforms, images, snapshots, instances) + +from functools import partial +import os + + +def collect_script(instance, base_dir, script, script_name): + """ + collect script data + instance: instance to run script on + base_dir: base directory for output data + script: script contents + script_name: name of script to run + return_value: None, may raise errors + """ + LOG.debug('running collect script: %s', script_name) + util.write_file(os.path.join(base_dir, script_name), + instance.run_script(script)) + + +def collect_test_data(args, snapshot, os_name, test_name): + """ + collect data for test case + args: cmdline arguments + snapshot: instantiated snapshot + test_name: name or path of test to run + return_value: tuple of results and fail count + """ + res = ({}, 1) + + # load test config + test_name = config.path_to_name(test_name) + test_config = config.load_test_config(test_name) + user_data = test_config['cloud_config'] + test_scripts = test_config['collect_scripts'] + test_output_dir = os.sep.join( + (args.data_dir, snapshot.platform_name, os_name, test_name)) + boot_timeout = (test_config.get('boot_timeout') + if isinstance(test_config.get('boot_timeout'), int) else + snapshot.config.get('timeout')) + + # if test is not enabled, skip and return 0 failures + if not test_config.get('enabled', False): + LOG.warn('test config %s is not enabled, skipping', test_name) + return ({}, 0) + + # create test instance + component = PlatformComponent( + partial(instances.get_instance, snapshot, user_data, + block=True, start=False, use_desc=test_name)) + + LOG.info('collecting test data for test: %s', test_name) + with component as instance: + start_call = partial(run_single, 'boot instance', partial( + instance.start, wait=True, wait_time=boot_timeout)) + collect_calls = [partial(run_single, 'script {}'.format(script_name), + partial(collect_script, instance, + test_output_dir, script, script_name)) + for script_name, script in test_scripts.items()] + + res = run_stage('collect for test: {}'.format(test_name), + [start_call] + collect_calls) + + return res + + +def collect_snapshot(args, image, os_name): + """ + collect data for snapshot of image + args: cmdline arguments + image: instantiated image with set up complete + return_value tuple of results and fail count + """ + res = ({}, 1) + + component = PlatformComponent(partial(snapshots.get_snapshot, image)) + + LOG.debug('creating snapshot for %s', os_name) + with component as snapshot: + LOG.info('collecting test data for os: %s', os_name) + res = run_stage( + 'collect test data for {}'.format(os_name), + [partial(collect_test_data, args, snapshot, os_name, test_name) + for test_name in args.test_config]) + + return res + + +def collect_image(args, platform, os_name): + """ + collect data for image + args: cmdline arguments + platform: instantiated platform + os_name: name of distro to collect for + return_value: tuple of results and fail count + """ + res = ({}, 1) + + os_config = config.load_os_config(os_name) + if not os_config.get('enabled'): + raise ValueError('OS {} not enabled'.format(os_name)) + + component = PlatformComponent( + partial(images.get_image, platform, os_config)) + + LOG.info('acquiring image for os: %s', os_name) + with component as image: + res = run_stage('set up and collect data for os: {}'.format(os_name), + [partial(setup_image.setup_image, args, image)] + + [partial(collect_snapshot, args, image, os_name)], + continue_after_error=False) + + return res + + +def collect_platform(args, platform_name): + """ + collect data for platform + args: cmdline arguments + platform_name: platform to collect for + return_value: tuple of results and fail count + """ + res = ({}, 1) + + platform_config = config.load_platform_config(platform_name) + if not platform_config.get('enabled'): + raise ValueError('Platform {} not enabled'.format(platform_name)) + + component = PlatformComponent( + partial(platforms.get_platform, platform_name, platform_config)) + + LOG.info('setting up platform: %s', platform_name) + with component as platform: + res = run_stage('collect for platform: {}'.format(platform_name), + [partial(collect_image, args, platform, os_name) + for os_name in args.os_name]) + + return res + + +def collect(args): + """ + entry point for collection + args: cmdline arguments + return_value: fail count + """ + (res, failed) = run_stage( + 'collect data', [partial(collect_platform, args, platform_name) + for platform_name in args.platform]) + + LOG.debug('collect stages: %s', res) + if args.result: + util.merge_results({'collect_stages': res}, args.result) + + return failed + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/config.py b/tests/cloud_tests/config.py new file mode 100644 index 00000000..f3a13c9a --- /dev/null +++ b/tests/cloud_tests/config.py @@ -0,0 +1,113 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +import glob +import os + +from cloudinit import util as c_util +from tests.cloud_tests import (BASE_DIR, TEST_CONF_DIR) + +# conf files +CONF_EXT = '.yaml' +VERIFY_EXT = '.py' +PLATFORM_CONF = os.path.join(BASE_DIR, 'platforms.yaml') +RELEASES_CONF = os.path.join(BASE_DIR, 'releases.yaml') +TESTCASE_CONF = os.path.join(BASE_DIR, 'testcases.yaml') + + +def path_to_name(path): + """ + convert abs or rel path to test config to path under configs/ + if already a test name, do nothing + """ + dir_path, file_name = os.path.split(os.path.normpath(path)) + name = os.path.splitext(file_name)[0] + return os.sep.join((os.path.basename(dir_path), name)) + + +def name_to_path(name): + """ + convert test config path under configs/ to full config path, + if already a full path, do nothing + """ + name = os.path.normpath(name) + if not name.endswith(CONF_EXT): + name = name + CONF_EXT + return name if os.path.isabs(name) else os.path.join(TEST_CONF_DIR, name) + + +def name_sanatize(name): + """ + sanatize test name to be used as a module name + """ + return name.replace('-', '_') + + +def name_to_module(name): + """ + convert test name to a loadable module name under testcases/ + """ + name = name_sanatize(path_to_name(name)) + return name.replace(os.path.sep, '.') + + +def merge_config(base, override): + """ + merge config and base + """ + res = base.copy() + res.update(override) + res.update({k: merge_config(base.get(k, {}), v) + for k, v in override.items() if isinstance(v, dict)}) + return res + + +def load_platform_config(platform): + """ + load configuration for platform + """ + main_conf = c_util.read_conf(PLATFORM_CONF) + return merge_config(main_conf.get('default_platform_config'), + main_conf.get('platforms')[platform]) + + +def load_os_config(os_name): + """ + load configuration for os + """ + main_conf = c_util.read_conf(RELEASES_CONF) + return merge_config(main_conf.get('default_release_config'), + main_conf.get('releases')[os_name]) + + +def load_test_config(path): + """ + load a test config file by either abs path or rel path + """ + return merge_config(c_util.read_conf(TESTCASE_CONF)['base_test_data'], + c_util.read_conf(name_to_path(path))) + + +def list_enabled_platforms(): + """ + list all platforms enabled for testing + """ + platforms = c_util.read_conf(PLATFORM_CONF).get('platforms') + return [k for k, v in platforms.items() if v.get('enabled')] + + +def list_enabled_distros(): + """ + list all distros enabled for testing + """ + releases = c_util.read_conf(RELEASES_CONF).get('releases') + return [k for k, v in releases.items() if v.get('enabled')] + + +def list_test_configs(): + """ + list all available test config files by abspath + """ + return [os.path.abspath(f) for f in + glob.glob(os.sep.join((TEST_CONF_DIR, '*', '*.yaml')))] + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/bugs/README.md b/tests/cloud_tests/configs/bugs/README.md new file mode 100644 index 00000000..09ce0765 --- /dev/null +++ b/tests/cloud_tests/configs/bugs/README.md @@ -0,0 +1,13 @@ +# Bug Test Configs + +## purpose +Configs that reproduce bugs filed against cloud-init. Having test configs for +cloud-init bugs ensures that the fixes do not break in the future, and makes it +easy to see how many systems and platforms are effected by a new bug. + +## structure +Should have one test config for most bugs filed. The name of the test should +contain ``lp`` followed by the bug number. It may also be useful to add a +comment to each bug config with a summary copied from the bug report. + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/bugs/lp1511485.yaml b/tests/cloud_tests/configs/bugs/lp1511485.yaml new file mode 100644 index 00000000..ebf9763f --- /dev/null +++ b/tests/cloud_tests/configs/bugs/lp1511485.yaml @@ -0,0 +1,11 @@ +# +# LP Bug 1511485: final_message is silent on ubuntu-12.04.5 / cloud-init 0.6.3 +# +# 2016-11-17: Disabled as covered by module based tests +# +enabled: False +cloud_config: | + #cloud-config + final_message: "Final message from cloud-config" + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/bugs/lp1611074.yaml b/tests/cloud_tests/configs/bugs/lp1611074.yaml new file mode 100644 index 00000000..960679d5 --- /dev/null +++ b/tests/cloud_tests/configs/bugs/lp1611074.yaml @@ -0,0 +1,8 @@ +# +# LP Bug 1611074: Reformatting of ephemeral drive fails on resize of Azure VM +# +# 2016-11-18: Disabled until test written +# +enabled: False + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/bugs/lp1628337.yaml b/tests/cloud_tests/configs/bugs/lp1628337.yaml new file mode 100644 index 00000000..1d6bf483 --- /dev/null +++ b/tests/cloud_tests/configs/bugs/lp1628337.yaml @@ -0,0 +1,20 @@ +# +# LP Bug 1628337: cloud-init tries to install NTP before even configuring the archives +# +cloud_config: | + #cloud-config + ntp: + servers: ['ntp.ubuntu.com'] + apt: + primary: + - arches: [default] + uri: http://us.archive.ubuntu.com/ubuntu/ +collect_sciprts: + ntp.conf: | + #!/bin/bash + cat /etc/ntp.conf + sources.list: | + #!/bin/bash + cat /etc/apt/sources.list + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/README.md b/tests/cloud_tests/configs/examples/README.md new file mode 100644 index 00000000..110a223b --- /dev/null +++ b/tests/cloud_tests/configs/examples/README.md @@ -0,0 +1,12 @@ +# Example Test Configs + +## Purpose +This folder contains example cloud configs found on +[cloudinit.readthedocs.io](https://cloudinit.readthedocs.io/en/latest/topics/examples.html). +Examples covered by other tests, like modules, are excluded from tests here +to prevent duplication and reduce test time. + +## Structure +One test per example test config on cloudinit.readthedocs.io + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/TODO.md b/tests/cloud_tests/configs/examples/TODO.md new file mode 100644 index 00000000..8db0e98e --- /dev/null +++ b/tests/cloud_tests/configs/examples/TODO.md @@ -0,0 +1,15 @@ +# Missing Examples + +Below lists each of the issing examples and why it is not currently added. + + - Chef (takes > 60 seconds to run) + - Puppet (takes > 60 seconds to run) + - Manage resolve.conf (lxd backend overrides changes) + - Adding a yum repository (need centos system) + - Register RedHat Subscription (need centos system + subscription) + - Adjust mount points mounted (need multiple disks) + - Call a url when finished (need end point) + - Reboot/poweroff when finished (how to test) + - Disk setup (need multiple disks) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/add_apt_repositories.yaml b/tests/cloud_tests/configs/examples/add_apt_repositories.yaml new file mode 100644 index 00000000..b8964357 --- /dev/null +++ b/tests/cloud_tests/configs/examples/add_apt_repositories.yaml @@ -0,0 +1,21 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as covered by module based tests +# +enabled: False +cloud_config: | + #cloud-config + apt: + primary: + - arches: [default] + uri: "http://www.gtlib.gatech.edu/pub/ubuntu-releases/" +collect_scripts: + ubuntu.sources.list: | + #!/bin/bash + cat /etc/apt/sources.list | grep -v '^#' | sed '/^\s*$/d' | grep archive.ubuntu.com | wc -l + gatech.sources.list: | + #!/bin/bash + cat /etc/apt/sources.list | grep -v '^#' | sed '/^\s*$/d' | grep gtlib.gatech.edu | wc -l + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/alter_completion_message.yaml b/tests/cloud_tests/configs/examples/alter_completion_message.yaml new file mode 100644 index 00000000..9e154f80 --- /dev/null +++ b/tests/cloud_tests/configs/examples/alter_completion_message.yaml @@ -0,0 +1,16 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as covered by module based tests +# +enabled: False +cloud_config: | + #cloud-config + final_message: | + This is my final message! + $version + $timestamp + $datasource + $uptime + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/configure_instance_trusted_ca_certificates.yaml b/tests/cloud_tests/configs/examples/configure_instance_trusted_ca_certificates.yaml new file mode 100644 index 00000000..ad32b088 --- /dev/null +++ b/tests/cloud_tests/configs/examples/configure_instance_trusted_ca_certificates.yaml @@ -0,0 +1,41 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as covered by module based tests +# +enabled: False +cloud_config: | + #cloud-config + ca-certs: + # If present and set to True, the 'remove-defaults' parameter will remove + # all the default trusted CA certificates that are normally shipped with + # Ubuntu. + # This is mainly for paranoid admins - most users will not need this + # functionality. + remove-defaults: true + + # If present, the 'trusted' parameter should contain a certificate (or list + # of certificates) to add to the system as trusted CA certificates. + # Pay close attention to the YAML multiline list syntax. The example shown + # here is for a list of multiline certificates. + trusted: + - | + -----BEGIN CERTIFICATE----- + YOUR-ORGS-TRUSTED-CA-CERT-HERE + -----END CERTIFICATE----- + - | + -----BEGIN CERTIFICATE----- + YOUR-ORGS-TRUSTED-CA-CERT-HERE + -----END CERTIFICATE----- +collect_scripts: + cloudinit_certs: | + #!/bin/bash + cat /etc/ssl/certs/cloud-init-ca-certs.pem + cert_count_ca: | + #!/bin/bash + wc -l /etc/ssl/certs/ca-certificates.crt + cert_count_cloudinit: | + #!/bin/bash + wc -l /etc/ssl/certs/cloud-init-ca-certs.pem + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/configure_instances_ssh_keys.yaml b/tests/cloud_tests/configs/examples/configure_instances_ssh_keys.yaml new file mode 100644 index 00000000..f3eaf3ce --- /dev/null +++ b/tests/cloud_tests/configs/examples/configure_instances_ssh_keys.yaml @@ -0,0 +1,63 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as covered by module based tests +# +enabled: False +cloud_config: | + #cloud-config + ssh_authorized_keys: + - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEA3FSyQwBI6Z+nCSjUUk8EEAnnkhXlukKoUPND/RRClWz2s5TCzIkd3Ou5+Cyz71X0XmazM3l5WgeErvtIwQMyT1KjNoMhoJMrJnWqQPOt5Q8zWd9qG7PBl9+eiH5qV7NZ mykey@host + - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3I7VUf2l5gSn5uavROsc5HRDpZdQueUq5ozemNSj8T7enqKHOEaFoU2VoPgGEWC9RyzSQVeyD6s7APMcE82EtmW4skVEgEGSbDc1pvxzxtchBj78hJP6Cf5TCMFSXw+Fz5rF1dR23QDbN1mkHs7adr8GW4kSWqU7Q7NDwfIrJJtO7Hi42GyXtvEONHbiRPOe8stqUly7MvUoN+5kfjBM8Qqpfl2+FNhTYWpMfYdPUnE7u536WqzFmsaqJctz3gBxH9Ex7dFtrxR4qiqEr9Qtlu3xGn7Bw07/+i1D+ey3ONkZLN+LQ714cgj8fRS4Hj29SCmXp5Kt5/82cD/VN3NtHw== smoser@brickies + + # Send pre-generated ssh private keys to the server + # If these are present, they will be written to /etc/ssh and + # new random keys will not be generated + # in addition to 'rsa' and 'dsa' as shown below, 'ecdsa' is also supported + ssh_keys: + rsa_private: | + -----BEGIN RSA PRIVATE KEY----- + MIIBxwIBAAJhAKD0YSHy73nUgysO13XsJmd4fHiFyQ+00R7VVu2iV9Qcon2LZS/x + 1cydPZ4pQpfjEha6WxZ6o8ci/Ea/w0n+0HGPwaxlEG2Z9inNtj3pgFrYcRztfECb + 1j6HCibZbAzYtwIBIwJgO8h72WjcmvcpZ8OvHSvTwAguO2TkR6mPgHsgSaKy6GJo + PUJnaZRWuba/HX0KGyhz19nPzLpzG5f0fYahlMJAyc13FV7K6kMBPXTRR6FxgHEg + L0MPC7cdqAwOVNcPY6A7AjEA1bNaIjOzFN2sfZX0j7OMhQuc4zP7r80zaGc5oy6W + p58hRAncFKEvnEq2CeL3vtuZAjEAwNBHpbNsBYTRPCHM7rZuG/iBtwp8Rxhc9I5w + ixvzMgi+HpGLWzUIBS+P/XhekIjPAjA285rVmEP+DR255Ls65QbgYhJmTzIXQ2T9 + luLvcmFBC6l35Uc4gTgg4ALsmXLn71MCMGMpSWspEvuGInayTCL+vEjmNBT+FAdO + W7D4zCpI43jRS9U06JVOeSc9CDk2lwiA3wIwCTB/6uc8Cq85D9YqpM10FuHjKpnP + REPPOyrAspdeOAV+6VKRavstea7+2DZmSUgE + -----END RSA PRIVATE KEY----- + + rsa_public: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEAoPRhIfLvedSDKw7XdewmZ3h8eIXJD7TRHtVW7aJX1ByifYtlL/HVzJ09nilCl+MSFrpbFnqjxyL8Rr/DSf7QcY/BrGUQbZn2Kc22PemAWthxHO18QJvWPocKJtlsDNi3 smoser@localhost + + dsa_private: | + -----BEGIN DSA PRIVATE KEY----- + MIIBuwIBAAKBgQDP2HLu7pTExL89USyM0264RCyWX/CMLmukxX0Jdbm29ax8FBJT + pLrO8TIXVY5rPAJm1dTHnpuyJhOvU9G7M8tPUABtzSJh4GVSHlwaCfycwcpLv9TX + DgWIpSj+6EiHCyaRlB1/CBp9RiaB+10QcFbm+lapuET+/Au6vSDp9IRtlQIVAIMR + 8KucvUYbOEI+yv+5LW9u3z/BAoGBAI0q6JP+JvJmwZFaeCMMVxXUbqiSko/P1lsa + LNNBHZ5/8MOUIm8rB2FC6ziidfueJpqTMqeQmSAlEBCwnwreUnGfRrKoJpyPNENY + d15MG6N5J+z81sEcHFeprryZ+D3Ge9VjPq3Tf3NhKKwCDQ0240aPezbnjPeFm4mH + bYxxcZ9GAoGAXmLIFSQgiAPu459rCKxT46tHJtM0QfnNiEnQLbFluefZ/yiI4DI3 + 8UzTCOXLhUA7ybmZha+D/csj15Y9/BNFuO7unzVhikCQV9DTeXX46pG4s1o23JKC + /QaYWNMZ7kTRv+wWow9MhGiVdML4ZN4XnifuO5krqAybngIy66PMEoQCFEIsKKWv + 99iziAH0KBMVbxy03Trz + -----END DSA PRIVATE KEY----- + + dsa_public: ssh-dsa AAAAB3NzaC1kc3MAAACBAM/Ycu7ulMTEvz1RLIzTbrhELJZf8Iwua6TFfQl1ubb1rHwUElOkus7xMhdVjms8AmbV1Meem7ImE69T0bszy09QAG3NImHgZVIeXBoJ/JzByku/1NcOBYilKP7oSIcLJpGUHX8IGn1GJoH7XRBwVub6Vqm4RP78C7q9IOn0hG2VAAAAFQCDEfCrnL1GGzhCPsr/uS1vbt8/wQAAAIEAjSrok/4m8mbBkVp4IwxXFdRuqJKSj8/WWxos00Ednn/ww5QibysHYULrOKJ1+54mmpMyp5CZICUQELCfCt5ScZ9GsqgmnI80Q1h3Xkwbo3kn7PzWwRwcV6muvJn4PcZ71WM+rdN/c2EorAINDTbjRo97NueM94WbiYdtjHFxn0YAAACAXmLIFSQgiAPu459rCKxT46tHJtM0QfnNiEnQLbFluefZ/yiI4DI38UzTCOXLhUA7ybmZha+D/csj15Y9/BNFuO7unzVhikCQV9DTeXX46pG4s1o23JKC/QaYWNMZ7kTRv+wWow9MhGiVdML4ZN4XnifuO5krqAybngIy66PMEoQ= smoser@localhost +collect_scripts: + cert_count: | + #!/bin/bash + ls | wc -l + dsa_public: | + #!/bin/bash + cat /etc/ssh/ssh_host_dsa_key.pub + rsa_public: | + #!/bin/bash + cat /etc/ssh/ssh_host_rsa_key.pub + auth_keys: | + #!/bin/bash + cat /home/ubuntu/.ssh/authorized_keys + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/including_user_groups.yaml b/tests/cloud_tests/configs/examples/including_user_groups.yaml new file mode 100644 index 00000000..0aa7ad21 --- /dev/null +++ b/tests/cloud_tests/configs/examples/including_user_groups.yaml @@ -0,0 +1,53 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as covered by module based tests +# +enabled: False +cloud_config: | + #cloud-config + # Add groups to the system + groups: + - secret: [foobar,barfoo] + - cloud-users + + # Add users to the system. Users are added after groups are added. + users: + - default + - name: foobar + gecos: Foo B. Bar + primary-group: foobar + groups: users + expiredate: 2038-01-19 + lock_passwd: false + passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/ + - name: barfoo + gecos: Bar B. Foo + sudo: ALL=(ALL) NOPASSWD:ALL + groups: cloud-users + lock_passwd: true + - name: cloudy + gecos: Magic Cloud App Daemon User + inactive: true + system: true +collect_scripts: + group_ubuntu: | + #!/bin/bash + getent group ubuntu + group_cloud_users: | + #!/bin/bash + getent group cloud-users + user_ubuntu: | + #!/bin/bash + getent passwd ubuntu + user_foobar: | + #!/bin/bash + getent passwd foobar + user_barfoo: | + #!/bin/bash + getent passwd barfoo + user_cloudy: | + #!/bin/bash + getent passwd cloudy + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/install_arbitrary_packages.yaml b/tests/cloud_tests/configs/examples/install_arbitrary_packages.yaml new file mode 100644 index 00000000..d3980228 --- /dev/null +++ b/tests/cloud_tests/configs/examples/install_arbitrary_packages.yaml @@ -0,0 +1,20 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as covered by module based tests +# +enabled: False +cloud_config: | + #cloud-config + packages: + - htop + - tree +collect_scripts: + htop: | + #!/bin/bash + dpkg -l | grep htop | wc -l + tree: | + #!/bin/bash + dpkg -l | grep tree | wc -l + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/install_run_chef_recipes.yaml b/tests/cloud_tests/configs/examples/install_run_chef_recipes.yaml new file mode 100644 index 00000000..3cd28dfe --- /dev/null +++ b/tests/cloud_tests/configs/examples/install_run_chef_recipes.yaml @@ -0,0 +1,94 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as test suite fails this long running test currently +# +enabled: False +cloud_config: | + #cloud-config + # Key from http://apt.opscode.com/packages@opscode.com.gpg.key + apt: + sources: + - source: "deb http://apt.opscode.com/ $RELEASE-0.10 main" + key: | + -----BEGIN PGP PUBLIC KEY BLOCK----- + Version: GnuPG v1.4.9 (GNU/Linux) + + mQGiBEppC7QRBADfsOkZU6KZK+YmKw4wev5mjKJEkVGlus+NxW8wItX5sGa6kdUu + twAyj7Yr92rF+ICFEP3gGU6+lGo0Nve7KxkN/1W7/m3G4zuk+ccIKmjp8KS3qn99 + dxy64vcji9jIllVa+XXOGIp0G8GEaj7mbkixL/bMeGfdMlv8Gf2XPpp9vwCgn/GC + JKacfnw7MpLKUHOYSlb//JsEAJqao3ViNfav83jJKEkD8cf59Y8xKia5OpZqTK5W + ShVnNWS3U5IVQk10ZDH97Qn/YrK387H4CyhLE9mxPXs/ul18ioiaars/q2MEKU2I + XKfV21eMLO9LYd6Ny/Kqj8o5WQK2J6+NAhSwvthZcIEphcFignIuobP+B5wNFQpe + DbKfA/0WvN2OwFeWRcmmd3Hz7nHTpcnSF+4QX6yHRF/5BgxkG6IqBIACQbzPn6Hm + sMtm/SVf11izmDqSsQptCrOZILfLX/mE+YOl+CwWSHhl+YsFts1WOuh1EhQD26aO + Z84HuHV5HFRWjDLw9LriltBVQcXbpfSrRP5bdr7Wh8vhqJTPjrQnT3BzY29kZSBQ + YWNrYWdlcyA8cGFja2FnZXNAb3BzY29kZS5jb20+iGAEExECACAFAkppC7QCGwMG + CwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRApQKupg++Caj8sAKCOXmdG36gWji/K + +o+XtBfvdMnFYQCfTCEWxRy2BnzLoBBFCjDSK6sJqCu5Ag0ESmkLtBAIAIO2SwlR + lU5i6gTOp42RHWW7/pmW78CwUqJnYqnXROrt3h9F9xrsGkH0Fh1FRtsnncgzIhvh + DLQnRHnkXm0ws0jV0PF74ttoUT6BLAUsFi2SPP1zYNJ9H9fhhK/pjijtAcQwdgxu + wwNJ5xCEscBZCjhSRXm0d30bK1o49Cow8ZIbHtnXVP41c9QWOzX/LaGZsKQZnaMx + EzDk8dyyctR2f03vRSVyTFGgdpUcpbr9eTFVgikCa6ODEBv+0BnCH6yGTXwBid9g + w0o1e/2DviKUWCC+AlAUOubLmOIGFBuI4UR+rux9affbHcLIOTiKQXv79lW3P7W8 + AAfniSQKfPWXrrcAAwUH/2XBqD4Uxhbs25HDUUiM/m6Gnlj6EsStg8n0nMggLhuN + QmPfoNByMPUqvA7sULyfr6xCYzbzRNxABHSpf85FzGQ29RF4xsA4vOOU8RDIYQ9X + Q8NqqR6pydprRFqWe47hsAN7BoYuhWqTtOLSBmnAnzTR5pURoqcquWYiiEavZixJ + 3ZRAq/HMGioJEtMFrvsZjGXuzef7f0ytfR1zYeLVWnL9Bd32CueBlI7dhYwkFe+V + Ep5jWOCj02C1wHcwt+uIRDJV6TdtbIiBYAdOMPk15+VBdweBXwMuYXr76+A7VeDL + zIhi7tKFo6WiwjKZq0dzctsJJjtIfr4K4vbiD9Ojg1iISQQYEQIACQUCSmkLtAIb + DAAKCRApQKupg++CauISAJ9CxYPOKhOxalBnVTLeNUkAHGg2gACeIsbobtaD4ZHG + 0GLl8EkfA8uhluM= + =zKAm + -----END PGP PUBLIC KEY BLOCK----- + + chef: + + # Valid values are 'gems' and 'packages' and 'omnibus' + install_type: "packages" + + # Boolean: run 'install_type' code even if chef-client + # appears already installed. + force_install: false + + # Chef settings + server_url: "https://chef.yourorg.com:4000" + + # Node Name + # Defaults to the instance-id if not present + node_name: "your-node-name" + + # Environment + # Defaults to '_default' if not present + environment: "production" + + # Default validation name is chef-validator + validation_name: "yourorg-validator" + # if validation_cert's value is "system" then it is expected + # that the file already exists on the system. + validation_cert: | + -----BEGIN RSA PRIVATE KEY----- + YOUR-ORGS-VALIDATION-KEY-HERE + -----END RSA PRIVATE KEY----- + + # A run list for a first boot json + run_list: + - "recipe[apache2]" + - "role[db]" + + # Specify a list of initial attributes used by the cookbooks + initial_attributes: + apache: + prefork: + maxclients: 100 + keepalive: "off" + + # if install_type is 'omnibus', change the url to download + omnibus_url: "https://www.opscode.com/chef/install.sh" + + + # Capture all subprocess output into a logfile + # Useful for troubleshooting cloud-init issues + output: {all: '| tee -a /var/log/cloud-init-output.log'} + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/run_apt_upgrade.yaml b/tests/cloud_tests/configs/examples/run_apt_upgrade.yaml new file mode 100644 index 00000000..2b7eae4c --- /dev/null +++ b/tests/cloud_tests/configs/examples/run_apt_upgrade.yaml @@ -0,0 +1,11 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as covered by module based tests +# +enabled: False +cloud_config: | + #cloud-config + package_upgrade: true + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/run_commands.yaml b/tests/cloud_tests/configs/examples/run_commands.yaml new file mode 100644 index 00000000..b0e311ba --- /dev/null +++ b/tests/cloud_tests/configs/examples/run_commands.yaml @@ -0,0 +1,16 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as covered by module based tests +# +enabled: False +cloud_config: | + #cloud-config + runcmd: + - echo cloud-init run cmd test > /tmp/run_cmd +collect_scripts: + run_cmd: | + #!/bin/bash + cat /tmp/run_cmd + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/run_commands_first_boot.yaml b/tests/cloud_tests/configs/examples/run_commands_first_boot.yaml new file mode 100644 index 00000000..7bd803db --- /dev/null +++ b/tests/cloud_tests/configs/examples/run_commands_first_boot.yaml @@ -0,0 +1,16 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as covered by module based tests +# +enabled: False +cloud_config: | + #cloud-config + bootcmd: + - echo 192.168.1.130 us.archive.ubuntu.com > /etc/hosts +collect_scripts: + hosts: | + #!/bin/bash + cat /etc/hosts + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/setup_run_puppet.yaml b/tests/cloud_tests/configs/examples/setup_run_puppet.yaml new file mode 100644 index 00000000..e366c042 --- /dev/null +++ b/tests/cloud_tests/configs/examples/setup_run_puppet.yaml @@ -0,0 +1,55 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as test suite fails this long running test currently +# +enabled: False +cloud_config: | + #cloud-config + puppet: + # Every key present in the conf object will be added to puppet.conf: + # [name] + # subkey=value + # + # For example the configuration below will have the following section + # added to puppet.conf: + # [puppetd] + # server=puppetmaster.example.org + # certname=i-0123456.ip-X-Y-Z.cloud.internal + # + # The puppmaster ca certificate will be available in + # /var/lib/puppet/ssl/certs/ca.pem + conf: + agent: + server: "puppetmaster.example.org" + # certname supports substitutions at runtime: + # %i: instanceid + # Example: i-0123456 + # %f: fqdn of the machine + # Example: ip-X-Y-Z.cloud.internal + # + # NB: the certname will automatically be lowercased as required by puppet + certname: "%i.%f" + # ca_cert is a special case. It won't be added to puppet.conf. + # It holds the puppetmaster certificate in pem format. + # It should be a multi-line string (using the | yaml notation for + # multi-line strings). + # The puppetmaster certificate is located in + # /var/lib/puppet/ssl/ca/ca_crt.pem on the puppetmaster host. + # + ca_cert: | + -----BEGIN CERTIFICATE----- + MIICCTCCAXKgAwIBAgIBATANBgkqhkiG9w0BAQUFADANMQswCQYDVQQDDAJjYTAe + Fw0xMDAyMTUxNzI5MjFaFw0xNTAyMTQxNzI5MjFaMA0xCzAJBgNVBAMMAmNhMIGf + MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu7Q40sm47/E1Pf+r8AYb/V/FWGPgc + b014OmNoX7dgCxTDvps/h8Vw555PdAFsW5+QhsGr31IJNI3kSYprFQcYf7A8tNWu + 1MASW2CfaEiOEi9F1R3R4Qlz4ix+iNoHiUDTjazw/tZwEdxaQXQVLwgTGRwVa+aA + qbutJKi93MILLwIDAQABo3kwdzA4BglghkgBhvhCAQ0EKxYpUHVwcGV0IFJ1Ynkv + T3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwDwYDVR0TAQH/BAUwAwEB/zAd + BgNVHQ4EFgQUu4+jHB+GYE5Vxo+ol1OAhevspjAwCwYDVR0PBAQDAgEGMA0GCSqG + SIb3DQEBBQUAA4GBAH/rxlUIjwNb3n7TXJcDJ6MMHUlwjr03BDJXKb34Ulndkpaf + +GAlzPXWa7bO908M9I8RnPfvtKnteLbvgTK+h+zX1XCty+S2EQWk29i2AdoqOTxb + hppiGMp0tT5Havu4aceCXiy2crVcudj3NFciy8X66SoECemW9UYDCb9T5D0d + -----END CERTIFICATE----- + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/examples/writing_out_arbitrary_files.yaml b/tests/cloud_tests/configs/examples/writing_out_arbitrary_files.yaml new file mode 100644 index 00000000..6f78f994 --- /dev/null +++ b/tests/cloud_tests/configs/examples/writing_out_arbitrary_files.yaml @@ -0,0 +1,45 @@ +# +# From cloud config examples on cloudinit.readthedocs.io +# +# 2016-11-17: Disabled as covered by module based tests +# +enabled: False +cloud_config: | + #cloud-config + write_files: + - encoding: b64 + content: CiMgVGhpcyBmaWxlIGNvbnRyb2xzIHRoZSBzdGF0ZSBvZiBTRUxpbnV4 + owner: root:root + path: /root/file_b64 + permissions: '0644' + - content: | + # My new /root/file_text + + SMBDOPTIONS="-D" + path: /root/file_text + - content: !!binary | + f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAwARAAAAAAABAAAAAAAAAAJAVAAAAAAAAAAAAAEAAOAAI + AEAAHgAdAAYAAAAFAAAAQAAAAAAAAABAAEAAAAAAAEAAQAAAAAAAwAEAAAAAAADAAQAAAAAAAAgA + AAAAAAAAAwAAAAQAAAAAAgAAAAAAAAACQAAAAAAAAAJAAAAAAAAcAAAAAAAAABwAAAAAAAAAAQAA + path: /root/file_binary + permissions: '0555' + - encoding: gzip + content: !!binary | + H4sIAIDb/U8C/1NW1E/KzNMvzuBKTc7IV8hIzcnJVyjPL8pJ4QIA6N+MVxsAAAA= + path: /root/file_gzip + permissions: '0755' +collect_scripts: + file_b64: | + #!/bin/bash + file /root/file_b64 + file_text: | + #!/bin/bash + file /root/file_text + file_binary: | + #!/bin/bash + file /root/file_binary + file_gzip: | + #!/bin/bash + file /root/file_gzip + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/main/README.md b/tests/cloud_tests/configs/main/README.md new file mode 100644 index 00000000..60346063 --- /dev/null +++ b/tests/cloud_tests/configs/main/README.md @@ -0,0 +1,11 @@ +# Main Functionality Test Configs + +## purpose +Test main features and config options of cloud-init such as logging, output +redirection, early init and integration with init system + +## structure +Should have one or more test configs for all main cloud-init output and logging +options, and basic functionality test cases + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/main/command_output_simple.yaml b/tests/cloud_tests/configs/main/command_output_simple.yaml new file mode 100644 index 00000000..08ca8940 --- /dev/null +++ b/tests/cloud_tests/configs/main/command_output_simple.yaml @@ -0,0 +1,13 @@ +# +# Test functionality of simple output redirection +# +cloud_config: | + #cloud-config + output: { all: "| tee -a /var/log/cloud-init-test-output" } + final_message: "should be last line in cloud-init-test-output file" +collect_scripts: + cloud-init-test-output: | + #!/bin/bash + cat /var/log/cloud-init-test-output + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/README.md b/tests/cloud_tests/configs/modules/README.md new file mode 100644 index 00000000..d66101f2 --- /dev/null +++ b/tests/cloud_tests/configs/modules/README.md @@ -0,0 +1,12 @@ +# Module Test Configs + +## Purpose +Test functionality of cloud config modules. See +[here](https://cloudinit.readthedocs.io/en/latest/topics/modules.html) for +a full list. + +## Structure +Should have one or more test configs for each module in cloudinit/config/. The +name of the test should indicate which module the config is verifying. + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/TODO.md b/tests/cloud_tests/configs/modules/TODO.md new file mode 100644 index 00000000..d496da95 --- /dev/null +++ b/tests/cloud_tests/configs/modules/TODO.md @@ -0,0 +1,100 @@ +# TODO + +The following lists complete or partially misisng modules. If a module is +listed with nothing below it indicates that no work is completed on that +module. If there is a list below the module name that is the remainig +identified work. + +## apt_configure + + * apt_get_wrapper + * What does this do? How to use it? + * apt_get_command + * To specify a different 'apt-get' command, set 'apt_get_command'. + This must be a list, and the subcommand (update, upgrade) is appended to it. + * Modify default and verify the options got passed correctly. + * preserve sources + * TBD + +## chef +2016-11-17: Tests took > 60 seconds and test framework times out currently. + +## disable EC2 metadata + +## disk setup + +## emit upstart + +## fan + +## growpart + +## grub dpkg + +## landscape +2016-11-17: Module is not working + +## lxd +2016-11-17: Need a zfs backed test written + +## mcollective + +## migrator + +## mounts + +## phone home + +## power state change + +## puppet +2016-11-17: Tests took > 60 seconds and test framework times out currently. + +## resizefs + +## resolv conf +2016-11-17: Issues with changing resolv.conf and lxc backend. + +## redhat subscription +2016-11-17: Need RH support in test framework. + +## rightscale userdata +2016-11-17: Specific to RightScale cloud enviornment. + +## rsyslog + +## scripts per boot +Not applicable to write a test for this as it specifies when something should be run. + +## scripts per instance +Not applicable to write a test for this as it specifies when something should be run. + +## scripts per once +Not applicable to write a test for this as it specifies when something should be run. + +## scripts user +Not applicable to write a test for this as it specifies when something should be run. + +## scripts vendor +Not applicable to write a test for this as it specifies when something should be run. + +## snappy +2016-11-17: Need test to install snaps from store + +## snap-config +2016-11-17: Need to investigate + +## spacewalk + +## ssh authkey fingerprints +The authkey_hash key does not appear to work. In fact the default claims to be md5, however syslog only shows sha256 + +## ubuntu init switch + +## update etc hosts +2016-11-17: Issues with changing /etc/hosts and lxc backend. + +## yum add repo +2016-11-17: Need RH support in test framework. + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/apt_configure_conf.yaml b/tests/cloud_tests/configs/modules/apt_configure_conf.yaml new file mode 100644 index 00000000..163ae3fc --- /dev/null +++ b/tests/cloud_tests/configs/modules/apt_configure_conf.yaml @@ -0,0 +1,19 @@ +# +# Provide a configuration for APT +# +cloud_config: | + #cloud-config + apt: + conf: | + APT { + Get { + Assume-Yes "true"; + Fix-Broken "true"; + } + } +collect_scripts: + 94cloud-init-config: | + #!/bin/bash + cat /etc/apt/apt.conf.d/94cloud-init-config + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/apt_configure_disable_suites.yaml b/tests/cloud_tests/configs/modules/apt_configure_disable_suites.yaml new file mode 100644 index 00000000..73e4a538 --- /dev/null +++ b/tests/cloud_tests/configs/modules/apt_configure_disable_suites.yaml @@ -0,0 +1,17 @@ +# +# Disables everything in sources.list +# +cloud_config: | + #cloud-config + apt: + disable_suites: + - $RELEASE + - $RELEASE-updates + - $RELEASE-backports + - $RELEASE-security +collect_scripts: + sources.list: | + #!/bin/bash + grep -v '^#' /etc/apt/sources.list | sed '/^\s*$/d' + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/apt_configure_primary.yaml b/tests/cloud_tests/configs/modules/apt_configure_primary.yaml new file mode 100644 index 00000000..2ec30ca1 --- /dev/null +++ b/tests/cloud_tests/configs/modules/apt_configure_primary.yaml @@ -0,0 +1,19 @@ +# +# Setup a custome primary sources.list +# +cloud_config: | + #cloud-config + apt: + primary: + - arches: + - default + uri: "http://www.gtlib.gatech.edu/pub/ubuntu-releases/" +collect_scripts: + ubuntu.sources.list: | + #!/bin/bash + grep -v '^#' /etc/apt/sources.list | sed '/^\s*$/d' | grep -c archive.ubuntu.com + gatech.sources.list: | + #!/bin/bash + grep -v '^#' /etc/apt/sources.list | sed '/^\s*$/d' | grep -c gtlib.gatech.edu + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/apt_configure_proxy.yaml b/tests/cloud_tests/configs/modules/apt_configure_proxy.yaml new file mode 100644 index 00000000..e7371305 --- /dev/null +++ b/tests/cloud_tests/configs/modules/apt_configure_proxy.yaml @@ -0,0 +1,16 @@ +# +# Set apt proxy +# +cloud_config: | + #cloud-config + apt: + proxy: "http://squid.internal:3128" + http_proxy: "http://squid.internal:3128" + ftp_proxy: "ftp://squid.internal:3128" + https_proxy: "https://squid.internal:3128" +collect_scripts: + 90cloud-init-aptproxy: | + #!/bin/bash + cat /etc/apt/apt.conf.d/90cloud-init-aptproxy + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/apt_configure_security.yaml b/tests/cloud_tests/configs/modules/apt_configure_security.yaml new file mode 100644 index 00000000..f6a2c828 --- /dev/null +++ b/tests/cloud_tests/configs/modules/apt_configure_security.yaml @@ -0,0 +1,15 @@ +# +# Add security to sources.list +# +cloud_config: | + #cloud-config + apt: + security: + - arches: + - default +collect_scripts: + sources.list: | + #!/bin/bash + grep -c security.ubuntu.com /etc/apt/sources.list + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/apt_configure_sources_key.yaml b/tests/cloud_tests/configs/modules/apt_configure_sources_key.yaml new file mode 100644 index 00000000..e7568a6a --- /dev/null +++ b/tests/cloud_tests/configs/modules/apt_configure_sources_key.yaml @@ -0,0 +1,47 @@ +# +# Add a sources.list entry with a given key (Debian Jessie) +# +cloud_config: | + #cloud-config + apt: + sources: + source1: + source: "deb http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu $RELEASE main" + key: | + -----BEGIN PGP PUBLIC KEY BLOCK----- + Version: SKS 1.1.6 + Comment: Hostname: keyserver.ubuntu.com + + mQINBFbZRUIBEAC+A0PIKYBP9kLC4hQtRrffRS11uLo8/BdtmOdrlW0hpPHzCfKnjR3tvSEI + lqPHG1QrrjAXKZDnZMRz+h/px7lUztvytGzHPSJd5ARUzAyjyRezUhoJ3VSCxrPqx62avuWf + RfoJaIeHfDehL5/dTVkyiWxfVZ369ZX6JN2AgLsQTeybTQ75+2z0xPrrhnGmgh6g0qTYcAaq + M5ONOGiqeSBX/Smjh6ALy5XkhUiFGLsI7Yluf6XSICY/x7gd6RAfgSIQrUTNMoS1sqhT4aot + +xvOfQy8ySkfAK4NddXql6E/+ZqTmBY/Lr0YklFBy8jGT+UysfiIznPMIwbmgq5Li7BtDDtX + b8Uyi4edPpjtextezfXYn4NVIpPL5dPZS/FXh4HpzyH0pYCfrH4QDGA7i52AGmhpiOFjJMo6 + N33sdjZHOH/2Vyp+QZaQnsdUAi1N4M6c33tQbpIScn1SY+El8z5JDA4PBzkw8HpLCi1gGoa6 + V4kfbWqXXbGAJFkLkP/vc4+pY9axOlmCkJg7xCPwhI75y1cONgovhz+BEXOzolh5KZuGbGbj + xe0wva5DLBeIg7EQFf+99pOS7Syby3Xpm6ZbswEFV0cllK4jf/QMjtfInxobuMoI0GV0bE5l + WlRtPCK5FnbHwxi0wPNzB/5fwzJ77r6HgPrR0OkT0lWmbUyoOQARAQABtC1MYXVuY2hwYWQg + UFBBIGZvciBjbG91ZCBpbml0IGRldmVsb3BtZW50IHRlYW2JAjgEEwECACIFAlbZRUICGwMG + CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEAg9Bvvk0wTfHfcP/REK5N2s1JYc69qEa9ZN + o6oi+A7l6AYw+ZY88O5TJe7F9otv5VXCIKSUT0Vsepjgf0mtXAgf/sb2lsJn/jp7tzgov3YH + vSrkTkRydz8xcA87gwQKePuvTLxQpftF4flrBxgSueIn5O/tPrBOxLz7EVYBc78SKg9aj9L2 + yUp+YuNevlwfZCTYeBb9r3FHaab2HcgkwqYch66+nKYfwiLuQ9NzXXm0Wn0JcEQ6pWvJscbj + C9BdawWovfvMK5/YLfI6Btm7F4mIpQBdhSOUp/YXKmdvHpmwxMCN2QhqYK49SM7qE9aUDbJL + arppSEBtlCLWhRBZYLTUna+BkuQ1bHz4St++XTR49Qd7vDERALpApDjB2dxPfMiBzCMwQQyq + uy13exU8o2ETLg+dZSLfDTzrBNsBFmXlw8WW17nTISYdKeGKL+QdlUjpzdwUMMzHhAO8SmMH + zjeSlDSRMXBJFAFSbCl7EwmMKa3yVX0zInT91fNllZ3iatAmtVdqVH/BFQfTIMH2ET7A8WzJ + ZzVSuMRhqoKdr5AMcHuJGPUoVkVJHQA+NNvEiXSysF3faL7jmKapmUwrhpYYX2H8pf+VMu2e + cLflKTI28dl+ZQ4Pl/aVsxrti/pzhdYy05Sn5ddtySyIkvo8L1cU5MWpbvSlFPkTstBUDLBf + pb0uBy+g0oxJQg15 + =uy53 + -----END PGP PUBLIC KEY BLOCK----- +collect_scripts: + sources.list: | + #!/bin/bash + cat /etc/apt/sources.list.d/source1.list + apt_key_list: | + #!/bin/bash + apt-key finger + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/apt_configure_sources_keyserver.yaml b/tests/cloud_tests/configs/modules/apt_configure_sources_keyserver.yaml new file mode 100644 index 00000000..1a4a238f --- /dev/null +++ b/tests/cloud_tests/configs/modules/apt_configure_sources_keyserver.yaml @@ -0,0 +1,20 @@ +# +# Add a sources.list entry with a key from a keyserver +# +cloud_config: | + #cloud-config + apt: + sources: + source1: + keyid: 0165013E + keyserver: keyserver.ubuntu.com + source: "deb http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu $RELEASE main" +collect_scripts: + sources.list: | + #!/bin/bash + cat /etc/apt/sources.list.d/source1.list + apt_key_list: | + #!/bin/bash + apt-key finger + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/apt_configure_sources_list.yaml b/tests/cloud_tests/configs/modules/apt_configure_sources_list.yaml new file mode 100644 index 00000000..057fc72c --- /dev/null +++ b/tests/cloud_tests/configs/modules/apt_configure_sources_list.yaml @@ -0,0 +1,19 @@ +# +# Generate a sources.list +# +cloud_config: | + #cloud-config + apt: + sources_list: | + deb $MIRROR $RELEASE main restricted + deb-src $MIRROR $RELEASE main restricted + deb $PRIMARY $RELEASE universe restricted + deb-src $PRIMARY $RELEASE universe restricted + deb $SECURITY $RELEASE-security multiverse + deb-src $SECURITY $RELEASE-security multiverse +collect_scripts: + sources.list: | + #/bin/bash + cat /etc/apt/sources.list + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/apt_configure_sources_ppa.yaml b/tests/cloud_tests/configs/modules/apt_configure_sources_ppa.yaml new file mode 100644 index 00000000..dee9dc70 --- /dev/null +++ b/tests/cloud_tests/configs/modules/apt_configure_sources_ppa.yaml @@ -0,0 +1,20 @@ +# +# Add a PPA to source.list +# +cloud_config: | + #cloud-config + apt: + sources: + source1: + keyid: 0165013E + keyserver: keyserver.ubuntu.com + source: "ppa:curtin-dev/test-archive" +collect_scripts: + sources.list: | + #!/bin/bash + cat /etc/apt/sources.list.d/curtin-dev-ubuntu-test-archive-*.list + apt-key: | + #!/bin/bash + apt-key finger + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/apt_pipelining_disable.yaml b/tests/cloud_tests/configs/modules/apt_pipelining_disable.yaml new file mode 100644 index 00000000..5fa0cee9 --- /dev/null +++ b/tests/cloud_tests/configs/modules/apt_pipelining_disable.yaml @@ -0,0 +1,13 @@ +# +# Disable apt pipelining value +# +cloud_config: | + #cloud-config + apt: + apt_pipelining: false +collect_scripts: + 90cloud-init-pipelining: | + #!/bin/bash + cat /etc/apt/apt.conf.d/90cloud-init-pipelining + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/apt_pipelining_os.yaml b/tests/cloud_tests/configs/modules/apt_pipelining_os.yaml new file mode 100644 index 00000000..87d183e7 --- /dev/null +++ b/tests/cloud_tests/configs/modules/apt_pipelining_os.yaml @@ -0,0 +1,13 @@ +# +# Set apt pipelining value to OS +# +cloud_config: | + #cloud-config + apt: + apt_pipelining: os +collect_scripts: + 90cloud-init-pipelining: | + #!/bin/bash + cat /etc/apt/apt.conf.d/90cloud-init-pipelining + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/bootcmd.yaml b/tests/cloud_tests/configs/modules/bootcmd.yaml new file mode 100644 index 00000000..3a73994e --- /dev/null +++ b/tests/cloud_tests/configs/modules/bootcmd.yaml @@ -0,0 +1,13 @@ +# +# Early boot command +# +cloud_config: | + #cloud-config + bootcmd: + - echo 192.168.1.130 us.archive.ubuntu.com > /etc/hosts +collect_scripts: + hosts: | + #!/bin/bash + cat /etc/hosts + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/byobu.yaml b/tests/cloud_tests/configs/modules/byobu.yaml new file mode 100644 index 00000000..fd648c77 --- /dev/null +++ b/tests/cloud_tests/configs/modules/byobu.yaml @@ -0,0 +1,18 @@ +# +# Install and enable byobu system wide and default user +# +cloud_config: | + #cloud-config + byobu_by_default: enable +collect_scripts: + byobu_installed: | + #!/bin/bash + which byobu + byobu_profile_enabled: | + #!/bin/bash + ls /etc/profile.d/Z97-byobu.sh + byobu_launch_exists: | + #!/bin/bash + which /usr/bin/byobu-launch + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/ca_certs.yaml b/tests/cloud_tests/configs/modules/ca_certs.yaml new file mode 100644 index 00000000..d939f435 --- /dev/null +++ b/tests/cloud_tests/configs/modules/ca_certs.yaml @@ -0,0 +1,52 @@ +# +# Remove existing ca_certs and install custom ca-cert +# +cloud_config: | + #cloud-config + ca-certs: + remove-defaults: true + trusted: + - | + -----BEGIN CERTIFICATE----- + MIIGJzCCBA+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBsjELMAkGA1UEBhMCRlIx + DzANBgNVBAgMBkFsc2FjZTETMBEGA1UEBwwKU3RyYXNib3VyZzEYMBYGA1UECgwP + d3d3LmZyZWVsYW4ub3JnMRAwDgYDVQQLDAdmcmVlbGFuMS0wKwYDVQQDDCRGcmVl + bGFuIFNhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIjAgBgkqhkiG9w0BCQEW + E2NvbnRhY3RAZnJlZWxhbi5vcmcwHhcNMTIwNDI3MTAzMTE4WhcNMjIwNDI1MTAz + MTE4WjB+MQswCQYDVQQGEwJGUjEPMA0GA1UECAwGQWxzYWNlMRgwFgYDVQQKDA93 + d3cuZnJlZWxhbi5vcmcxEDAOBgNVBAsMB2ZyZWVsYW4xDjAMBgNVBAMMBWFsaWNl + MSIwIAYJKoZIhvcNAQkBFhNjb250YWN0QGZyZWVsYW4ub3JnMIICIjANBgkqhkiG + 9w0BAQEFAAOCAg8AMIICCgKCAgEA3W29+ID6194bH6ejLrIC4hb2Ugo8v6ZC+Mrc + k2dNYMNPjcOKABvxxEtBamnSaeU/IY7FC/giN622LEtV/3oDcrua0+yWuVafyxmZ + yTKUb4/GUgafRQPf/eiX9urWurtIK7XgNGFNUjYPq4dSJQPPhwCHE/LKAykWnZBX + RrX0Dq4XyApNku0IpjIjEXH+8ixE12wH8wt7DEvdO7T3N3CfUbaITl1qBX+Nm2Z6 + q4Ag/u5rl8NJfXg71ZmXA3XOj7zFvpyapRIZcPmkvZYn7SMCp8dXyXHPdpSiIWL2 + uB3KiO4JrUYvt2GzLBUThp+lNSZaZ/Q3yOaAAUkOx+1h08285Pi+P8lO+H2Xic4S + vMq1xtLg2bNoPC5KnbRfuFPuUD2/3dSiiragJ6uYDLOyWJDivKGt/72OVTEPAL9o + 6T2pGZrwbQuiFGrGTMZOvWMSpQtNl+tCCXlT4mWqJDRwuMGrI4DnnGzt3IKqNwS4 + Qyo9KqjMIPwnXZAmWPm3FOKe4sFwc5fpawKO01JZewDsYTDxVj+cwXwFxbE2yBiF + z2FAHwfopwaH35p3C6lkcgP2k/zgAlnBluzACUI+MKJ/G0gv/uAhj1OHJQ3L6kn1 + SpvQ41/ueBjlunExqQSYD7GtZ1Kg8uOcq2r+WISE3Qc9MpQFFkUVllmgWGwYDuN3 + Zsez95kCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNT + TCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFFlfyRO6G8y5qEFKikl5 + ajb2fT7XMB8GA1UdIwQYMBaAFCNsLT0+KV14uGw+quK7Lh5sh/JTMA0GCSqGSIb3 + DQEBBQUAA4ICAQAT5wJFPqervbja5+90iKxi1d0QVtVGB+z6aoAMuWK+qgi0vgvr + mu9ot2lvTSCSnRhjeiP0SIdqFMORmBtOCFk/kYDp9M/91b+vS+S9eAlxrNCB5VOf + PqxEPp/wv1rBcE4GBO/c6HcFon3F+oBYCsUQbZDKSSZxhDm3mj7pb67FNbZbJIzJ + 70HDsRe2O04oiTx+h6g6pW3cOQMgIAvFgKN5Ex727K4230B0NIdGkzuj4KSML0NM + slSAcXZ41OoSKNjy44BVEZv0ZdxTDrRM4EwJtNyggFzmtTuV02nkUj1bYYYC5f0L + ADr6s0XMyaNk8twlWYlYDZ5uKDpVRVBfiGcq0uJIzIvemhuTrofh8pBQQNkPRDFT + Rq1iTo1Ihhl3/Fl1kXk1WR3jTjNb4jHX7lIoXwpwp767HAPKGhjQ9cFbnHMEtkro + RlJYdtRq5mccDtwT0GFyoJLLBZdHHMHJz0F9H7FNk2tTQQMhK5MVYwg+LIaee586 + CQVqfbscp7evlgjLW98H+5zylRHAgoH2G79aHljNKMp9BOuq6SnEglEsiWGVtu2l + hnx8SB3sVJZHeer8f/UQQwqbAO+Kdy70NmbSaqaVtp8jOxLiidWkwSyRTsuU6D8i + DiH5uEqBXExjrj0FslxcVKdVj5glVcSmkLwZKbEU1OKwleT/iXFhvooWhQ== + -----END CERTIFICATE----- +collect_scripts: + cert_count: | + #!/bin/bash + ls -l /etc/ssl/certs | wc -l + cert: | + #!/bin/bash + md5sum /etc/ssl/certs/ca-certificates.crt +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/debug_disable.yaml b/tests/cloud_tests/configs/modules/debug_disable.yaml new file mode 100644 index 00000000..63218b18 --- /dev/null +++ b/tests/cloud_tests/configs/modules/debug_disable.yaml @@ -0,0 +1,9 @@ +# +# Do not run in debug mode +# +cloud_config: | + #cloud-config + debug: + verbose: False + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/debug_enable.yaml b/tests/cloud_tests/configs/modules/debug_enable.yaml new file mode 100644 index 00000000..d44147db --- /dev/null +++ b/tests/cloud_tests/configs/modules/debug_enable.yaml @@ -0,0 +1,9 @@ +# +# Run in debug mode +# +cloud_config: | + #cloud-config + debug: + verbose: True + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/final_message.yaml b/tests/cloud_tests/configs/modules/final_message.yaml new file mode 100644 index 00000000..c9ed6118 --- /dev/null +++ b/tests/cloud_tests/configs/modules/final_message.yaml @@ -0,0 +1,13 @@ +# +# Print a final message with various predefined variables +# +cloud_config: | + #cloud-config + final_message: | + This is my final message! + $version + $timestamp + $datasource + $uptime + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/keys_to_console.yaml b/tests/cloud_tests/configs/modules/keys_to_console.yaml new file mode 100644 index 00000000..a90e42c1 --- /dev/null +++ b/tests/cloud_tests/configs/modules/keys_to_console.yaml @@ -0,0 +1,13 @@ +# +# Hide printing of ssh key and fingerprints for specific keys +# +cloud_config: | + #cloud-config + ssh_fp_console_blacklist: [ssh-dss, ssh-dsa, ecdsa-sha2-nistp256] + ssh_key_console_blacklist: [ssh-dss, ssh-dsa, ecdsa-sha2-nistp256] +collect_scripts: + syslog: | + #!/bin/bash + cat /var/log/syslog + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/landscape.yaml b/tests/cloud_tests/configs/modules/landscape.yaml new file mode 100644 index 00000000..e6f4955a --- /dev/null +++ b/tests/cloud_tests/configs/modules/landscape.yaml @@ -0,0 +1,26 @@ +# +# Setup landscape client settings +# +# 2016-11-17: Disabled due to this not working +# +enabled: false +cloud_config: | + #cloud-conifg + landscape: + client: + log_level: "info" + url: "https://landscape.canonical.com/message-system" + ping_url: "http://landscape.canonical.com/ping" + data_path: "/var/lib/landscape/client" + http_proxy: "http://my.proxy.com/foobar" + https_proxy: "https://my.proxy.com/foobar" + tags: "server,cloud" + computer_title: "footitle" + registration_key: "fookey" + account_name: "fooaccount" +collect_scripts: + client.conf: | + #!/bin/bash + cat /etc/landscape/client.conf + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/locale.yaml b/tests/cloud_tests/configs/modules/locale.yaml new file mode 100644 index 00000000..af5ad636 --- /dev/null +++ b/tests/cloud_tests/configs/modules/locale.yaml @@ -0,0 +1,19 @@ +# +# Set locale to non-default option and verify +# +cloud_config: | + #cloud-config + locale: en_GB.UTF-8 + locale_configfile: /etc/default/locale +collect_scripts: + locale_default: | + #!/bin/bash + cat /etc/default/locale + locale_a: | + #!/bin/bash + locale -a + locale_gen: | + #!/bin/bash + cat /etc/locale.gen | grep -v '^#' | uniq + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/lxd_bridge.yaml b/tests/cloud_tests/configs/modules/lxd_bridge.yaml new file mode 100644 index 00000000..568bb700 --- /dev/null +++ b/tests/cloud_tests/configs/modules/lxd_bridge.yaml @@ -0,0 +1,30 @@ +# +# LXD configured with directory backend and IPv4 bridge +# +cloud_config: | + #cloud-config + lxd: + init: + storage_backend: dir + bridge: + mode: new + name: lxdbr0 + ipv4_address: 10.100.100.1 + ipv4_netmask: 24 + ipv4_dhcp_first: 10.100.100.100 + ipv4_dhcp_last: 10.100.100.200 + ipv4_nat: true + domain: lxd +collect_scripts: + lxc: | + #!/bin/bash + which lxc + lxd: | + #!/bin/bash + which lxd + lxc-bridge: | + #!/bin/bash + ip addr show lxdbr0 + cat /etc/default/lxd-bridge 2>/dev/null | grep -v ^# | sort -u + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/lxd_dir.yaml b/tests/cloud_tests/configs/modules/lxd_dir.yaml new file mode 100644 index 00000000..99b92195 --- /dev/null +++ b/tests/cloud_tests/configs/modules/lxd_dir.yaml @@ -0,0 +1,17 @@ +# +# LXD configured with directory backend +# +cloud_config: | + #cloud-config + lxd: + init: + storage_backend: dir +collect_scripts: + lxc: | + #!/bin/bash + which lxc + lxd: | + #!/bin/bash + which lxd + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/ntp.yaml b/tests/cloud_tests/configs/modules/ntp.yaml new file mode 100644 index 00000000..d0941578 --- /dev/null +++ b/tests/cloud_tests/configs/modules/ntp.yaml @@ -0,0 +1,20 @@ +# +# Emtpy NTP config to setup using defaults +# +cloud_config: | + #cloud-config + ntp: + pools: {} + servers: {} +collect_scripts: + ntp_installed_empty: | + #!/bin/bash + dpkg -l | grep ntp | wc -l + ntp_conf_dist_empty: | + #!/bin/bash + ls /etc/ntp.conf.dist | wc -l + ntp_conf_empty: | + #!/bin/bash + grep '^pool' /etc/ntp.conf + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/ntp_pools.yaml b/tests/cloud_tests/configs/modules/ntp_pools.yaml new file mode 100644 index 00000000..bd0ac292 --- /dev/null +++ b/tests/cloud_tests/configs/modules/ntp_pools.yaml @@ -0,0 +1,23 @@ +# +# NTP config using specific pools +# +cloud_config: | + #cloud-config + ntp: + pools: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 2.pool.ntp.org + - 3.pool.ntp.org +collect_scripts: + ntp_installed_pools: | + #!/bin/bash + dpkg -l | grep ntp | wc -l + ntp_conf_dist_pools: | + #!/bin/bash + ls /etc/ntp.conf.dist | wc -l + ntp_conf_pools: | + #!/bin/bash + grep '^pool' /etc/ntp.conf + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/ntp_servers.yaml b/tests/cloud_tests/configs/modules/ntp_servers.yaml new file mode 100644 index 00000000..934b9c5d --- /dev/null +++ b/tests/cloud_tests/configs/modules/ntp_servers.yaml @@ -0,0 +1,20 @@ +# +# NTP config using specific servers +# +cloud_config: | + #cloud-config + ntp: + servers: + - pool.ntp.org +collect_scripts: + ntp_installed_servers: | + #!/bin/bash + dpkg -l | grep ntp | wc -l + ntp_conf_dist_servers: | + #!/bin/bash + ls /etc/ntp.conf.dist | wc -l + ntp_conf_servers: | + #!/bin/bash + grep '^server' /etc/ntp.conf + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/package_update_upgrade_install.yaml b/tests/cloud_tests/configs/modules/package_update_upgrade_install.yaml new file mode 100644 index 00000000..d027d540 --- /dev/null +++ b/tests/cloud_tests/configs/modules/package_update_upgrade_install.yaml @@ -0,0 +1,22 @@ +# +# Update/upgrade via apt and then install a pair of packages +# +cloud_config: | + #cloud-config + packages: + - htop + - tree + package_update: true + package_upgrade: true +collect_scripts: + apt_history_cmdline: | + #!/bin/bash + grep ^Commandline: /var/log/apt/history.log + dpkg_htop: | + #!/bin/bash + dpkg -l | grep htop | wc -l + dpkg_tree: | + #!/bin/bash + dpkg -l | grep tree | wc -l + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/runcmd.yaml b/tests/cloud_tests/configs/modules/runcmd.yaml new file mode 100644 index 00000000..04e5a050 --- /dev/null +++ b/tests/cloud_tests/configs/modules/runcmd.yaml @@ -0,0 +1,13 @@ +# +# Run a simple command +# +cloud_config: | + #cloud-config + runcmd: + - echo cloud-init run cmd test > /tmp/run_cmd +collect_scripts: + run_cmd: | + #!/bin/bash + cat /tmp/run_cmd + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/salt_minion.yaml b/tests/cloud_tests/configs/modules/salt_minion.yaml new file mode 100644 index 00000000..f20d24f0 --- /dev/null +++ b/tests/cloud_tests/configs/modules/salt_minion.yaml @@ -0,0 +1,34 @@ +# +# Create config for a salt minion +# +# 2016-11-17: Currently takes >60 seconds results in test failure +# +enabled: False +cloud_config: | + #cloud-config + salt_minion: + conf: + master: salt.mydomain.com + public_key: | + ------BEGIN PUBLIC KEY------- + <key data> + ------END PUBLIC KEY------- + private_key: | + ------BEGIN PRIVATE KEY------ + <key data> + ------END PRIVATE KEY------- +collect_scripts: + minion: | + #!/bin/bash + cat /etc/salt/minion + minion_id: | + #!/bin/bash + cat /etc/salt/minion_id + minion.pem: | + #!/bin/bash + cat /etc/salt/pki/minion/minion.pem + minion.pub: | + #!/bin/bash + cat /etc/salt/pki/minion/minion.pub + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/seed_random_command.yaml b/tests/cloud_tests/configs/modules/seed_random_command.yaml new file mode 100644 index 00000000..6a9157eb --- /dev/null +++ b/tests/cloud_tests/configs/modules/seed_random_command.yaml @@ -0,0 +1,18 @@ +# +# Use uuid to create a random string +# +# 2016-11-15 Disabled as this is not working currently +# +enabled: False +cloud_config: | + #cloud-config + random_seed: + command: ["cat", "/proc/sys/kernel/random/uuid"] + command_required: true + file: /root/seed +collect_scripts: + seed_data: | + #!/bin/bash + cat /root/seed + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/seed_random_data.yaml b/tests/cloud_tests/configs/modules/seed_random_data.yaml new file mode 100644 index 00000000..a9b2c885 --- /dev/null +++ b/tests/cloud_tests/configs/modules/seed_random_data.yaml @@ -0,0 +1,15 @@ +# +# Push in random raw string to set as seed +# +cloud_config: | + #cloud-config + random_seed: + data: 'MYUb34023nD:LFDK10913jk;dfnk:Df' + encoding: raw + file: /root/seed +collect_scripts: + seed_data: | + #!/bin/bash + cat /root/seed + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/set_hostname.yaml b/tests/cloud_tests/configs/modules/set_hostname.yaml new file mode 100644 index 00000000..5aae1506 --- /dev/null +++ b/tests/cloud_tests/configs/modules/set_hostname.yaml @@ -0,0 +1,18 @@ +# +# Set the hostname and update /etc/hosts +# +cloud_config: | + #cloud-config + hostname: myhostname +collect_scripts: + hosts: | + #!/bin/bash + grep ^127 /etc/hosts + hostname: | + #!/bin/bash + hostname + fqdn: | + #!/bin/bash + hostname --fqdn + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/set_hostname_fqdn.yaml b/tests/cloud_tests/configs/modules/set_hostname_fqdn.yaml new file mode 100644 index 00000000..0014c197 --- /dev/null +++ b/tests/cloud_tests/configs/modules/set_hostname_fqdn.yaml @@ -0,0 +1,20 @@ +# +# Set the hostname and update /etc/hosts +# +cloud_config: | + #cloud-config + manage_etc_hosts: true + hostname: myhostname + fqdn: host.myorg.com +collect_scripts: + hosts: | + #!/bin/bash + grep ^127 /etc/hosts + hostname: | + #!/bin/bash + hostname + fqdn: | + #!/bin/bash + hostname --fqdn + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/set_password.yaml b/tests/cloud_tests/configs/modules/set_password.yaml new file mode 100644 index 00000000..8fa46d9f --- /dev/null +++ b/tests/cloud_tests/configs/modules/set_password.yaml @@ -0,0 +1,17 @@ +# +# Set password of default user +# +cloud_config: | + #cloud-config + password: password + chpasswd: { expire: False } + ssh_pwauth: True +collect_scripts: + shadow: | + #!/bin/bash + cat /etc/shadow + sshd_config: | + #!/bin/bash + grep '^PasswordAuth' /etc/ssh/sshd_config + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/set_password_expire.yaml b/tests/cloud_tests/configs/modules/set_password_expire.yaml new file mode 100644 index 00000000..926731f0 --- /dev/null +++ b/tests/cloud_tests/configs/modules/set_password_expire.yaml @@ -0,0 +1,28 @@ +# +# Expire password for all users +# +cloud_config: | + #cloud-config + chpasswd: { expire: True } + users: + - name: tom + password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. + lock_passwd: false + - name: dick + password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. + lock_passwd: false + - name: harry + password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. + lock_passwd: false + - name: jane + password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. + lock_passwd: false +collect_scripts: + shadow: | + #!/bin/bash + cat /etc/shadow + sshd_config: | + #!/bin/bash + grep '^PasswordAuth' /etc/ssh/sshd_config + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/set_password_list.yaml b/tests/cloud_tests/configs/modules/set_password_list.yaml new file mode 100644 index 00000000..36129047 --- /dev/null +++ b/tests/cloud_tests/configs/modules/set_password_list.yaml @@ -0,0 +1,33 @@ +# +# Set password of list of users +# +cloud_config: | + #cloud-config + ssh_pwauth: yes + users: + - name: tom + password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. + lock_passwd: false + - name: dick + password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. + lock_passwd: false + - name: harry + password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. + lock_passwd: false + - name: jane + password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE. + lock_passwd: false + chpasswd: + list: | + tom:mypassword123! + dick:R + harry:Random +collect_scripts: + shadow: | + #!/bin/bash + cat /etc/shadow + sshd_config: | + #!/bin/bash + grep '^PasswordAuth' /etc/ssh/sshd_config + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/snappy.yaml b/tests/cloud_tests/configs/modules/snappy.yaml new file mode 100644 index 00000000..923bfe12 --- /dev/null +++ b/tests/cloud_tests/configs/modules/snappy.yaml @@ -0,0 +1,13 @@ +# +# Install snappy +# +cloud_config: | + #cloud-config + snappy: + system_snappy: auto +collect_scripts: + snap_version: | + #!/bin/bash + snap --version + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/ssh_auth_key_fingerprints_disable.yaml b/tests/cloud_tests/configs/modules/ssh_auth_key_fingerprints_disable.yaml new file mode 100644 index 00000000..33943bdd --- /dev/null +++ b/tests/cloud_tests/configs/modules/ssh_auth_key_fingerprints_disable.yaml @@ -0,0 +1,13 @@ +# +# Disable fingerprint printing +# +cloud_config: | + #cloud-config + ssh_genkeytypes: [] + no_ssh_fingerprints: true +collect_scripts: + syslog: | + #!/bin/bash + cat /var/log/syslog + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/ssh_auth_key_fingerprints_enable.yaml b/tests/cloud_tests/configs/modules/ssh_auth_key_fingerprints_enable.yaml new file mode 100644 index 00000000..4c970778 --- /dev/null +++ b/tests/cloud_tests/configs/modules/ssh_auth_key_fingerprints_enable.yaml @@ -0,0 +1,16 @@ +# +# Print auth keys with different hash than md5 +# +cloud_config: | + #cloud-config + ssh_genkeytypes: + - ecdsa + - ed25519 + ssh_authorized_keys: + - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDXW9Gg5H7ehjdSc6qDzwNtgCy94XYHhEYlXZMO2+FJrH3wfHGiMfCwOHxcOMt2QiXItULthdeQWS9QjBSSjVRXf6731igFrqPFyS9qBlOQ5D29C4HBXFnQggGVpBNJ82IRJv7szbbe/vpgLBP4kttUza9Dr4e1YM1ln4PRnjfXea6T0m+m1ixNb5432pTXlqYOnNOxSIm1gHgMLxPuDrJvQERDKrSiKSjIdyC9Jd8t2e1tkNLY0stmckVRbhShmcJvlyofHWbc2Ca1mmtP7MlS1VQnfLkvU1IrFwkmaQmaggX6WR6coRJ6XFXdWcq/AI2K6GjSnl1dnnCxE8VCEXBlXgFzad+PMSG4yiL5j8Oo1ZVpkTdgBnw4okGqTYCXyZg6X00As9IBNQfZMFlQXlIo4FiWgj3CO5QHQOyOX6FuEumaU13GnERrSSdp9tCs1Qm3/DG2RSCQBWTfcgMcStIvKqvJ3IjFn0vGLvI3Ampnq9q1SHwmmzAPSdzcMA76HyMUA5VWaBvWHlUxzIM6unxZASnwvuCzpywSEB5J2OF+p6H+cStJwQ32XwmOG8pLp1srlVWpqZI58Du/lzrkPqONphoZx0LDV86w7RUz1ksDzAdcm0tvmNRFMN1a0frDs506oA3aWK0oDk4Nmvk8sXGTYYw3iQSkOvDUUlIsqdaO+w== +collect_scripts: + syslog: | + #!/bin/bash + cat /var/log/syslog + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/ssh_import_id.yaml b/tests/cloud_tests/configs/modules/ssh_import_id.yaml new file mode 100644 index 00000000..6e5a1635 --- /dev/null +++ b/tests/cloud_tests/configs/modules/ssh_import_id.yaml @@ -0,0 +1,14 @@ +# +# Import a user's ssh key via gh or lp +# +cloud_config: | + #cloud-config + ssh_import_id: + - gh:powersj + - lp:smoser +collect_scripts: + auth_keys_ubuntu: | + #!/bin/bash + cat /home/ubuntu/.ssh/authorized_keys + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/ssh_keys_generate.yaml b/tests/cloud_tests/configs/modules/ssh_keys_generate.yaml new file mode 100644 index 00000000..637d7835 --- /dev/null +++ b/tests/cloud_tests/configs/modules/ssh_keys_generate.yaml @@ -0,0 +1,42 @@ +# +# SSH keys generated using cloud-init +# +cloud_config: | + #cloud-config + ssh_genkeytypes: + - ecdsa + - ed25519 + authkey_hash: sha512 +collect_scripts: + auth_keys_root: | + #!/bin/bash + cat /root/.ssh/authorized_keys + auth_keys_ubuntu: | + #!/bin/bash + cat /home/ubuntu/ssh/authorized_keys + dsa_public: | + #!/bin/bash + cat /etc/ssh/ssh_host_dsa_key.pub + dsa_private: | + #!/bin/bash + cat /etc/ssh/ssh_host_dsa_key + rsa_public: | + #!/bin/bash + cat /etc/ssh/ssh_host_rsa_key.pub + rsa_private: | + #!/bin/bash + cat /etc/ssh/ssh_host_rsa_key + ecdsa_public: | + #!/bin/bash + cat /etc/ssh/ssh_host_ecdsa_key.pub + ecdsa_private: | + #!/bin/bash + cat /etc/ssh/ssh_host_ecdsa_key + ed25519_public: | + #!/bin/bash + cat /etc/ssh/ssh_host_ed25519_key.pub + ed25519_private: | + #!/bin/bash + cat /etc/ssh/ssh_host_ed25519_key + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/ssh_keys_provided.yaml b/tests/cloud_tests/configs/modules/ssh_keys_provided.yaml new file mode 100644 index 00000000..25df6452 --- /dev/null +++ b/tests/cloud_tests/configs/modules/ssh_keys_provided.yaml @@ -0,0 +1,102 @@ +# +# SSH keys provided via cloud config +# +enabled: False +cloud_config: | + #cloud-config + disable_root: false + ssh_authorized_keys: + - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDXW9Gg5H7ehjdSc6qDzwNtgCy94XYHhEYlXZMO2+FJrH3wfHGiMfCwOHxcOMt2QiXItULthdeQWS9QjBSSjVRXf6731igFrqPFyS9qBlOQ5D29C4HBXFnQggGVpBNJ82IRJv7szbbe/vpgLBP4kttUza9Dr4e1YM1ln4PRnjfXea6T0m+m1ixNb5432pTXlqYOnNOxSIm1gHgMLxPuDrJvQERDKrSiKSjIdyC9Jd8t2e1tkNLY0stmckVRbhShmcJvlyofHWbc2Ca1mmtP7MlS1VQnfLkvU1IrFwkmaQmaggX6WR6coRJ6XFXdWcq/AI2K6GjSnl1dnnCxE8VCEXBlXgFzad+PMSG4yiL5j8Oo1ZVpkTdgBnw4okGqTYCXyZg6X00As9IBNQfZMFlQXlIo4FiWgj3CO5QHQOyOX6FuEumaU13GnERrSSdp9tCs1Qm3/DG2RSCQBWTfcgMcStIvKqvJ3IjFn0vGLvI3Ampnq9q1SHwmmzAPSdzcMA76HyMUA5VWaBvWHlUxzIM6unxZASnwvuCzpywSEB5J2OF+p6H+cStJwQ32XwmOG8pLp1srlVWpqZI58Du/lzrkPqONphoZx0LDV86w7RUz1ksDzAdcm0tvmNRFMN1a0frDs506oA3aWK0oDk4Nmvk8sXGTYYw3iQSkOvDUUlIsqdaO+w== + ssh_keys: + rsa_private: | + -----BEGIN RSA PRIVATE KEY----- + MIIEowIBAAKCAQEAtPx6PqN3iSEsnTtibyIEy52Tra8T5fn0ryXyg46Di2NBwdnj + o8trNv9jenfV/UhmePl58lXjT43wV8OCMl6KsYXyBdegM35NNtono4I4mLLKFMR9 + 9TOtDn6iYcaNenVhF3ZCj9Z2nNOlTrdc0uchHqKMrxLjCRCUrL91Uf+xioTF901Y + RM+ZqC5lT92yAL76F4qPF+Lq1QtUfNfUIwwvOp5ccDZLPxij0YvyBzubYye9hJHu + yjbJv78R4JHV+L2WhzSoX3W/6WrxVzeXqFGqH894ccOaC/7tnqSP6V8lIQ6fE2+c + DurJcpM3CJRgkndGHjtU55Y71YkcdLksSMvezQIDAQABAoIBAQCrU4IJP8dNeaj5 + IpkY6NQvR/jfZqfogYi+MKb1IHin/4rlDfUvPcY9pt8ttLlObjYK+OcWn3Vx/sRw + 4DOkqNiUGl80Zp1RgZNohHUXlJMtAbrIlAVEk+mTmg7vjfyp2unRQvLZpMRdywBm + lq95OrCghnG03aUsFJUZPpi5ydnwbA12ma+KHkG0EzaVlhA7X9N6z0K6U+zue2gl + goMLt/MH0rsYawkHrwiwXaIFQeyV4MJP0vmrZLbFk1bycu9X/xPtTYotWyWo4eKA + cb05uu04qwexkKHDM0KXtT0JecbTo2rOefFo8Uuab6uJY+fEHNocZ+v1vLA4aOxJ + ovp1JuXlAoGBAOWYNgKrlTfy5n0sKsNk+1RuL2jHJZJ3HMd0EIt7/fFQN3Fi08Hu + jtntqD30Wj+DJK8b8Lrt66FruxyEJm5VhVmwkukrLR5ige2f6ftZnoFCmdyy+0zP + dnPZSUe2H5ZPHa+qthJgHLn+al2P04tGh+1fGHC2PbP+e0Co+/ZRIOxrAoGBAMnN + IEen9/FRsqvnDd36I8XnJGskVRTZNjylxBmbKcuMWm+gNhOI7gsCAcqzD4BYZjjW + pLhrt/u9p+l4MOJy6OUUdM/okg12SnJEGryysOcVBcXyrvOfklWnANG4EAH5jt1N + ftTb1XTxzvWVuR/WJK0B5MZNYM71cumBdUDtPi+nAoGAYmoIXMSnxb+8xNL10aOr + h9ljQQp8NHgSQfyiSufvRk0YNuYh1vMnEIsqnsPrG2Zfhx/25GmvoxXGssaCorDN + 5FAn6QK06F1ZTD5L0Y3sv4OI6G1gAuC66ZWuL6sFhyyKkQ4f1WiVZ7SCa3CHQSAO + i9VDaKz1bf4bXvAQcNj9v9kCgYACSOZCqW4vN0OUmqsXhkt9ZB6Pb/veno70pNPR + jmYsvcwQU3oJQpWfXkhy6RAV3epaXmPDCsUsfns2M3wqNC7a2R5xdCqjKGGzZX4A + AO3rz9se4J6Gd5oKijeCKFlWDGNHsibrdgm2pz42nZlY+O21X74dWKbt8O16I1MW + hxkbJQKBgAXfuen/srVkJgPuqywUYag90VWCpHsuxdn+fZJa50SyZADr+RbiDfH2 + vek8Uo8ap8AEsv4Rfs9opUcUZevLp3g2741eOaidHVLm0l4iLIVl03otGOqvSzs+ + A3tFPEOxauXpzCt8f8eXsz0WQXAgIKW2h8zu5QHjomioU3i27mtE + -----END RSA PRIVATE KEY----- + rsa_public: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0/Ho+o3eJISydO2JvIgTLnZOtrxPl+fSvJfKDjoOLY0HB2eOjy2s2/2N6d9X9SGZ4+XnyVeNPjfBXw4IyXoqxhfIF16Azfk022iejgjiYssoUxH31M60OfqJhxo16dWEXdkKP1nac06VOt1zS5yEeooyvEuMJEJSsv3VR/7GKhMX3TVhEz5moLmVP3bIAvvoXio8X4urVC1R819QjDC86nlxwNks/GKPRi/IHO5tjJ72Eke7KNsm/vxHgkdX4vZaHNKhfdb/pavFXN5eoUaofz3hxw5oL/u2epI/pXyUhDp8Tb5wO6slykzcIlGCSd0YeO1TnljvViRx0uSxIy97N root@xenial-lxd + dsa_private: | + -----BEGIN DSA PRIVATE KEY----- + MIIBuwIBAAKBgQD5Fstc23IVSDe6k4DNP8smPKuEWUvHDTOGaXrhOVAfzZ6+jklP + 55mzvC7jO53PWWC31hq10xBoWdev0WtcNF9Tv+4bAa1263y51Rqo4GI7xx+xic1d + mLqqfYijBT9k48J/1tV0cs1Wjs6FP/IJTD/kYVC930JjYQMi722lBnUxsQIVAL7i + z3fTGKTvSzvW0wQlwnYpS2QFAoGANp+KdyS9V93HgxGQEN1rlj/TSv/a3EVdCKtE + nQf55aPHxDAVDVw5JtRh4pZbbRV4oGRPc9KOdjo5BU28vSM3Lmhkb+UaaDXwHkgI + nK193o74DKjADWZxuLyyiKHiMOhxozoxDfjWxs8nz6uqvSW0pr521EwIY6RajbED + nZ2a3GkCgYEAyoUomNRB6bmpsIfzt8zdtqLP5umIj2uhr9MVPL8/QdbxmJ72Z7pf + Q2z1B7QAdIBGOlqJXtlau7ABhWK29Efe+99ObyTSSdDc6RCDeAwUmBAiPRQhDH2E + wExw3doDSCUb28L1B50wBzQ8mC3KXp6C7IkBXWspb16DLHUHFSI8bkICFA5kVUcW + nCPOXEQsayANi8+Cb7BH + -----END DSA PRIVATE KEY----- + dsa_public: ssh-dss AAAAB3NzaC1kc3MAAACBAPkWy1zbchVIN7qTgM0/yyY8q4RZS8cNM4ZpeuE5UB/Nnr6OSU/nmbO8LuM7nc9ZYLfWGrXTEGhZ16/Ra1w0X1O/7hsBrXbrfLnVGqjgYjvHH7GJzV2Yuqp9iKMFP2Tjwn/W1XRyzVaOzoU/8glMP+RhUL3fQmNhAyLvbaUGdTGxAAAAFQC+4s930xik70s71tMEJcJ2KUtkBQAAAIA2n4p3JL1X3ceDEZAQ3WuWP9NK/9rcRV0Iq0SdB/nlo8fEMBUNXDkm1GHillttFXigZE9z0o52OjkFTby9IzcuaGRv5RpoNfAeSAicrX3ejvgMqMANZnG4vLKIoeIw6HGjOjEN+NbGzyfPq6q9JbSmvnbUTAhjpFqNsQOdnZrcaQAAAIEAyoUomNRB6bmpsIfzt8zdtqLP5umIj2uhr9MVPL8/QdbxmJ72Z7pfQ2z1B7QAdIBGOlqJXtlau7ABhWK29Efe+99ObyTSSdDc6RCDeAwUmBAiPRQhDH2EwExw3doDSCUb28L1B50wBzQ8mC3KXp6C7IkBXWspb16DLHUHFSI8bkI= root@xenial-lxd + ed25519_private: | + -----BEGIN OPENSSH PRIVATE KEY----- + b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW + QyNTUxOQAAACDbnQGUruL42aVVsyHeaV5mYNTOhteXao0Nl5DVThJ2+QAAAJgwt+lcMLfp + XAAAAAtzc2gtZWQyNTUxOQAAACDbnQGUruL42aVVsyHeaV5mYNTOhteXao0Nl5DVThJ2+Q + AAAEDQlFZpz9q8+/YJHS9+jPAqy2ZT6cGEv8HTB6RZtTjd/dudAZSu4vjZpVWzId5pXmZg + 1M6G15dqjQ2XkNVOEnb5AAAAD3Jvb3RAeGVuaWFsLWx4ZAECAwQFBg== + -----END OPENSSH PRIVATE KEY----- + ed25519_public: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINudAZSu4vjZpVWzId5pXmZg1M6G15dqjQ2XkNVOEnb5 root@xenial-lxd + ecdsa_private: | + -----BEGIN EC PRIVATE KEY----- + MHcCAQEEIDuK+QFc1wmyJY8uDqQVa1qHte30Rk/fdLxGIBkwJAyOoAoGCCqGSM49 + AwEHoUQDQgAEWxLlO+TL8gL91eET9p/HFQbqR1A691AkJgZk3jY5mpZqxgX4vcgb + 7f/CtXuM6s2svcDJqAeXr6Wk8OJJcMxylA== + -----END EC PRIVATE KEY----- + ecdsa_public: ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFsS5Tvky/IC/dXhE/afxxUG6kdQOvdQJCYGZN42OZqWasYF+L3IG+3/wrV7jOrNrL3AyagHl6+lpPDiSXDMcpQ= root@xenial-lxd +collect_scripts: + auth_keys_root: | + #!/bin/bash + cat /root/.ssh/authorized_keys + auth_keys_ubuntu: | + #!/bin/bash + cat /home/ubuntu/ssh/authorized_keys + dsa_public: | + #!/bin/bash + cat /etc/ssh/ssh_host_dsa_key.pub + dsa_private: | + #!/bin/bash + cat /etc/ssh/ssh_host_dsa_key + rsa_public: | + #!/bin/bash + cat /etc/ssh/ssh_host_rsa_key.pub + rsa_private: | + #!/bin/bash + cat /etc/ssh/ssh_host_rsa_key + ecdsa_public: | + #!/bin/bash + cat /etc/ssh/ssh_host_ecdsa_key.pub + ecdsa_private: | + #!/bin/bash + cat /etc/ssh/ssh_host_ecdsa_key + ed25519_public: | + #!/bin/bash + cat /etc/ssh/ssh_host_ed25519_key.pub + ed25519_private: | + #!/bin/bash + cat /etc/ssh/ssh_host_ed25519_key + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/timezone.yaml b/tests/cloud_tests/configs/modules/timezone.yaml new file mode 100644 index 00000000..6a05aba1 --- /dev/null +++ b/tests/cloud_tests/configs/modules/timezone.yaml @@ -0,0 +1,12 @@ +# +# Set system timezone +# +cloud_config: | + #cloud-config + timezone: US/Aleutian +collect_scripts: + timezone: | + #!/bin/bash + date +%Z + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/user_groups.yaml b/tests/cloud_tests/configs/modules/user_groups.yaml new file mode 100644 index 00000000..92655958 --- /dev/null +++ b/tests/cloud_tests/configs/modules/user_groups.yaml @@ -0,0 +1,50 @@ +# +# Create groups and users with various options +# +cloud_config: | + #cloud-config + # Add groups to the system + groups: + - secret: [foobar,barfoo] + - cloud-users + + # Add users to the system. Users are added after groups are added. + users: + - default + - name: foobar + gecos: Foo B. Bar + primary-group: foobar + groups: users + expiredate: 2038-01-19 + lock_passwd: false + passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/ + - name: barfoo + gecos: Bar B. Foo + sudo: ALL=(ALL) NOPASSWD:ALL + groups: cloud-users + lock_passwd: true + - name: cloudy + gecos: Magic Cloud App Daemon User + inactive: true + system: true +collect_scripts: + group_ubuntu: | + #!/bin/bash + getent group ubuntu + group_cloud_users: | + #!/bin/bash + getent group cloud-users + user_ubuntu: | + #!/bin/bash + getent passwd ubuntu + user_foobar: | + #!/bin/bash + getent passwd foobar + user_barfoo: | + #!/bin/bash + getent passwd barfoo + user_cloudy: | + #!/bin/bash + getent passwd cloudy + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/configs/modules/write_files.yaml b/tests/cloud_tests/configs/modules/write_files.yaml new file mode 100644 index 00000000..4bb2991a --- /dev/null +++ b/tests/cloud_tests/configs/modules/write_files.yaml @@ -0,0 +1,42 @@ +# +# Write various file types +# +cloud_config: | + #cloud-config + write_files: + - encoding: b64 + content: CiMgVGhpcyBmaWxlIGNvbnRyb2xzIHRoZSBzdGF0ZSBvZiBTRUxpbnV4 + owner: root:root + path: /root/file_b64 + permissions: '0644' + - content: | + # My new /root/file_text + + SMBDOPTIONS="-D" + path: /root/file_text + - content: !!binary | + f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAwARAAAAAAABAAAAAAAAAAJAVAAAAAAAAAAAAAEAAOAAI + AEAAHgAdAAYAAAAFAAAAQAAAAAAAAABAAEAAAAAAAEAAQAAAAAAAwAEAAAAAAADAAQAAAAAAAAgA + AAAAAAAAAwAAAAQAAAAAAgAAAAAAAAACQAAAAAAAAAJAAAAAAAAcAAAAAAAAABwAAAAAAAAAAQAA + path: /root/file_binary + permissions: '0555' + - encoding: gzip + content: !!binary | + H4sIAIDb/U8C/1NW1E/KzNMvzuBKTc7IV8hIzcnJVyjPL8pJ4QIA6N+MVxsAAAA= + path: /root/file_gzip + permissions: '0755' +collect_scripts: + file_b64: | + #!/bin/bash + file /root/file_b64 + file_text: | + #!/bin/bash + file /root/file_text + file_binary: | + #!/bin/bash + file /root/file_binary + file_gzip: | + #!/bin/bash + file /root/file_gzip + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/images/__init__.py b/tests/cloud_tests/images/__init__.py new file mode 100644 index 00000000..b27d6931 --- /dev/null +++ b/tests/cloud_tests/images/__init__.py @@ -0,0 +1,11 @@ +# This file is part of cloud-init. See LICENSE file for license information. + + +def get_image(platform, config): + """ + get image from platform object using os_name, looking up img_conf in main + config file + """ + return platform.get_image(config) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/images/base.py b/tests/cloud_tests/images/base.py new file mode 100644 index 00000000..394b11ff --- /dev/null +++ b/tests/cloud_tests/images/base.py @@ -0,0 +1,65 @@ +# This file is part of cloud-init. See LICENSE file for license information. + + +class Image(object): + """ + Base class for images + """ + platform_name = None + + def __init__(self, name, config, platform): + """ + setup + """ + self.name = name + self.config = config + self.platform = platform + + def __str__(self): + """ + a brief description of the image + """ + return '-'.join((self.properties['os'], self.properties['release'])) + + @property + def properties(self): + """ + {} containing: 'arch', 'os', 'version', 'release' + """ + raise NotImplementedError + + # FIXME: instead of having execute and push_file and other instance methods + # here which pass through to a hidden instance, it might be better + # to expose an instance that the image can be modified through + def execute(self, command, stdin=None, stdout=None, stderr=None, env={}): + """ + execute command in image, modifying image + """ + raise NotImplementedError + + def push_file(self, local_path, remote_path): + """ + copy file at 'local_path' to instance at 'remote_path', modifying image + """ + raise NotImplementedError + + def run_script(self, script): + """ + run script in image, modifying image + return_value: script output + """ + raise NotImplementedError + + def snapshot(self): + """ + create snapshot of image, block until done + """ + raise NotImplementedError + + def destroy(self): + """ + clean up data associated with image + """ + pass + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/images/lxd.py b/tests/cloud_tests/images/lxd.py new file mode 100644 index 00000000..7a416141 --- /dev/null +++ b/tests/cloud_tests/images/lxd.py @@ -0,0 +1,92 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from tests.cloud_tests.images import base +from tests.cloud_tests.snapshots import lxd as lxd_snapshot + + +class LXDImage(base.Image): + """ + LXD backed image + """ + platform_name = "lxd" + + def __init__(self, name, config, platform, pylxd_image): + """ + setup + """ + self.platform = platform + self._pylxd_image = pylxd_image + self._instance = None + super(LXDImage, self).__init__(name, config, platform) + + @property + def pylxd_image(self): + self._pylxd_image.sync() + return self._pylxd_image + + @property + def instance(self): + if not self._instance: + self._instance = self.platform.launch_container( + image=self.pylxd_image.fingerprint, + image_desc=str(self), use_desc='image-modification') + self._instance.start(wait=True, wait_time=self.config.get('timeout')) + return self._instance + + @property + def properties(self): + """ + {} containing: 'arch', 'os', 'version', 'release' + """ + properties = self.pylxd_image.properties + return { + 'arch': properties.get('architecture'), + 'os': properties.get('os'), + 'version': properties.get('version'), + 'release': properties.get('release'), + } + + def execute(self, *args, **kwargs): + """ + execute command in image, modifying image + """ + return self.instance.execute(*args, **kwargs) + + def push_file(self, local_path, remote_path): + """ + copy file at 'local_path' to instance at 'remote_path', modifying image + """ + return self.instance.push_file(local_path, remote_path) + + def run_script(self, script): + """ + run script in image, modifying image + return_value: script output + """ + return self.instance.run_script(script) + + def snapshot(self): + """ + create snapshot of image, block until done + """ + # clone current instance, start and freeze clone + instance = self.platform.launch_container( + container=self.instance.name, image_desc=str(self), + use_desc='snapshot') + instance.start(wait=True, wait_time=self.config.get('timeout')) + if self.config.get('boot_clean_script'): + instance.run_script(self.config.get('boot_clean_script')) + instance.freeze() + return lxd_snapshot.LXDSnapshot( + self.properties, self.config, self.platform, instance) + + def destroy(self): + """ + clean up data associated with image + """ + if self._instance: + self._instance.destroy() + self.pylxd_image.delete(wait=True) + super(LXDImage, self).destroy() + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/instances/__init__.py b/tests/cloud_tests/instances/__init__.py new file mode 100644 index 00000000..85bea99f --- /dev/null +++ b/tests/cloud_tests/instances/__init__.py @@ -0,0 +1,10 @@ +# This file is part of cloud-init. See LICENSE file for license information. + + +def get_instance(snapshot, *args, **kwargs): + """ + get instance from snapshot + """ + return snapshot.launch(*args, **kwargs) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/instances/base.py b/tests/cloud_tests/instances/base.py new file mode 100644 index 00000000..9559d286 --- /dev/null +++ b/tests/cloud_tests/instances/base.py @@ -0,0 +1,120 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +import os +import uuid + + +class Instance(object): + """ + Base instance object + """ + platform_name = None + + def __init__(self, name): + """ + setup + """ + self.name = name + + def execute(self, command, stdin=None, stdout=None, stderr=None, env={}): + """ + command: the command to execute as root inside the image + stdin, stderr, stdout: file handles + env: environment variables + + Execute assumes functional networking and execution as root with the + target filesystem being available at /. + + return_value: tuple containing stdout data, stderr data, exit code + """ + raise NotImplementedError + + def read_data(self, remote_path, encode=False): + """ + read_data from instance filesystem + remote_path: path in instance + decode: return as string + return_value: data as str or bytes + """ + raise NotImplementedError + + def write_data(self, remote_path, data): + """ + write data to instance filesystem + remote_path: path in instance + data: data to write, either str or bytes + """ + raise NotImplementedError + + def pull_file(self, remote_path, local_path): + """ + copy file at 'remote_path', from instance to 'local_path' + """ + with open(local_path, 'wb') as fp: + fp.write(self.read_data(remote_path), encode=True) + + def push_file(self, local_path, remote_path): + """ + copy file at 'local_path' to instance at 'remote_path' + """ + with open(local_path, 'rb') as fp: + self.write_data(remote_path, fp.read()) + + def run_script(self, script): + """ + run script in target and return stdout + """ + script_path = os.path.join('/tmp', str(uuid.uuid1())) + self.write_data(script_path, script) + (out, err, exit_code) = self.execute(['/bin/bash', script_path]) + return out + + def console_log(self): + """ + return_value: bytes of this instance’s console + """ + raise NotImplementedError + + def reboot(self, wait=True): + """ + reboot instance + """ + raise NotImplementedError + + def shutdown(self, wait=True): + """ + shutdown instance + """ + raise NotImplementedError + + def start(self, wait=True): + """ + start instance + """ + raise NotImplementedError + + def destroy(self): + """ + clean up instance + """ + pass + + def _wait_for_cloud_init(self, wait_time): + """ + wait until system has fully booted and cloud-init has finished + """ + if not wait_time: + return + + found_msg = 'found' + cmd = ('for ((i=0;i<{wait};i++)); do [ -f "{file}" ] && ' + '{{ echo "{msg}";break; }} || sleep 1; done').format( + file='/run/cloud-init/result.json', + wait=wait_time, msg=found_msg) + + (out, err, exit) = self.execute(['/bin/bash', '-c', cmd]) + if out.strip() != found_msg: + raise OSError('timeout: after {}s, cloud-init has not started' + .format(wait_time)) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/instances/lxd.py b/tests/cloud_tests/instances/lxd.py new file mode 100644 index 00000000..f0aa1214 --- /dev/null +++ b/tests/cloud_tests/instances/lxd.py @@ -0,0 +1,121 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from tests.cloud_tests.instances import base + + +class LXDInstance(base.Instance): + """ + LXD container backed instance + """ + platform_name = "lxd" + + def __init__(self, name, platform, pylxd_container): + """ + setup + """ + self.platform = platform + self._pylxd_container = pylxd_container + super(LXDInstance, self).__init__(name) + + @property + def pylxd_container(self): + self._pylxd_container.sync() + return self._pylxd_container + + def execute(self, command, stdin=None, stdout=None, stderr=None, env={}): + """ + command: the command to execute as root inside the image + stdin, stderr, stdout: file handles + env: environment variables + + Execute assumes functional networking and execution as root with the + target filesystem being available at /. + + return_value: tuple containing stdout data, stderr data, exit code + """ + # TODO: the pylxd api handler for container.execute needs to be + # extended to properly pass in stdin + # TODO: the pylxd api handler for container.execute needs to be + # extended to get the return code, for now just use 0 + self.start() + if stdin: + raise NotImplementedError + res = self.pylxd_container.execute(command, environment=env) + for (f, data) in (i for i in zip((stdout, stderr), res) if i[0]): + f.write(data) + return res + (0,) + + def read_data(self, remote_path, decode=False): + """ + read data from instance filesystem + remote_path: path in instance + decode: return as string + return_value: data as str or bytes + """ + data = self.pylxd_container.files.get(remote_path) + return data.decode() if decode and isinstance(data, bytes) else data + + def write_data(self, remote_path, data): + """ + write data to instance filesystem + remote_path: path in instance + data: data to write, either str or bytes + """ + self.pylxd_container.files.put(remote_path, data) + + def console_log(self): + """ + return_value: bytes of this instance’s console + """ + raise NotImplementedError + + def reboot(self, wait=True): + """ + reboot instance + """ + self.shutdown(wait=wait) + self.start(wait=wait) + + def shutdown(self, wait=True): + """ + shutdown instance + """ + if self.pylxd_container.status != 'Stopped': + self.pylxd_container.stop(wait=wait) + + def start(self, wait=True, wait_time=None): + """ + start instance + """ + if self.pylxd_container.status != 'Running': + self.pylxd_container.start(wait=wait) + if wait and isinstance(wait_time, int): + self._wait_for_cloud_init(wait_time) + + def freeze(self): + """ + freeze instance + """ + if self.pylxd_container.status != 'Frozen': + self.pylxd_container.freeze(wait=True) + + def unfreeze(self): + """ + unfreeze instance + """ + if self.pylxd_container.status == 'Frozen': + self.pylxd_container.unfreeze(wait=True) + + def destroy(self): + """ + clean up instance + """ + self.unfreeze() + self.shutdown() + self.pylxd_container.delete(wait=True) + if self.platform.container_exists(self.name): + raise OSError('container {} was not properly removed' + .format(self.name)) + super(LXDInstance, self).destroy() + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/manage.py b/tests/cloud_tests/manage.py new file mode 100644 index 00000000..5342612b --- /dev/null +++ b/tests/cloud_tests/manage.py @@ -0,0 +1,75 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from tests.cloud_tests.config import VERIFY_EXT +from tests.cloud_tests import (config, util) +from tests.cloud_tests import TESTCASES_DIR + +import os +import textwrap + +_verifier_fmt = textwrap.dedent( + """ + \"\"\"cloud-init Integration Test Verify Script\"\"\" + from tests.cloud_tests.testcases import base + + + class {test_class}(base.CloudTestCase): + \"\"\" + Name: {test_name} + Category: {test_category} + Description: {test_description} + \"\"\" + pass + """ +).lstrip() +_config_fmt = textwrap.dedent( + """ + # + # Name: {test_name} + # Category: {test_category} + # Description: {test_description} + # + {config} + """ +).strip() + + +def write_testcase_config(args, fmt_args, testcase_file): + """ + write the testcase config file + """ + testcase_config = {'enabled': args.enable, 'collect_scripts': {}} + if args.config: + testcase_config['cloud_config'] = args.config + fmt_args['config'] = util.yaml_format(testcase_config) + util.write_file(testcase_file, _config_fmt.format(**fmt_args), omode='w') + + +def write_verifier(args, fmt_args, verifier_file): + """ + write the verifier script + """ + fmt_args['test_class'] = 'Test{}'.format( + config.name_sanatize(fmt_args['test_name']).title()) + util.write_file(verifier_file, _verifier_fmt.format(**fmt_args), omode='w') + + +def create(args): + """ + create a new testcase + """ + (test_category, test_name) = args.name.split('/') + fmt_args = {'test_name': test_name, 'test_category': test_category, + 'test_description': str(args.description)} + + testcase_file = config.name_to_path(args.name) + verifier_file = os.path.join( + TESTCASES_DIR, test_category, + config.name_sanatize(test_name) + VERIFY_EXT) + + write_testcase_config(args, fmt_args, testcase_file) + write_verifier(args, fmt_args, verifier_file) + + return 0 + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/platforms.yaml b/tests/cloud_tests/platforms.yaml new file mode 100644 index 00000000..5972b32b --- /dev/null +++ b/tests/cloud_tests/platforms.yaml @@ -0,0 +1,17 @@ +# ============================= Platform Config =============================== +default_platform_config: + # all disabled by default + enabled: false + # maximum time to retrieve image + get_image_timeout: 300 + # maximum time to create instance (before waiting for cloud-init) + create_instance_timeout: 60 + +platforms: + lxd: + enabled: true + get_image_timeout: 600 + ec2: {} + azure: {} + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/platforms/__init__.py b/tests/cloud_tests/platforms/__init__.py new file mode 100644 index 00000000..f9f56035 --- /dev/null +++ b/tests/cloud_tests/platforms/__init__.py @@ -0,0 +1,19 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from tests.cloud_tests.platforms import lxd + +PLATFORMS = { + 'lxd': lxd.LXDPlatform, +} + + +def get_platform(platform_name, config): + """ + Get the platform object for 'platform_name' and init + """ + platform_cls = PLATFORMS.get(platform_name) + if not platform_cls: + raise ValueError('invalid platform name: {}'.format(platform_name)) + return platform_cls(config) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/platforms/base.py b/tests/cloud_tests/platforms/base.py new file mode 100644 index 00000000..615e2e06 --- /dev/null +++ b/tests/cloud_tests/platforms/base.py @@ -0,0 +1,53 @@ +# This file is part of cloud-init. See LICENSE file for license information. + + +class Platform(object): + """ + Base class for platforms + """ + platform_name = None + + def __init__(self, config): + """ + Set up platform + """ + self.config = config + + def get_image(self, img_conf): + """ + Get image using 'img_conf', where img_conf is a dict containing all + image configuration parameters + + in this dict there must be a 'platform_ident' key containing + configuration for identifying each image on a per platform basis + + see implementations for get_image() for details about the contents + of the platform's config entry + + note: see 'releases' main_config.yaml for example entries + + img_conf: configuration for image + return_value: cloud_tests.images instance + """ + raise NotImplementedError + + def destroy(self): + """ + Clean up platform data + """ + pass + + def _extract_img_platform_config(self, img_conf): + """ + extract platform configuration for current platform from img_conf + """ + platform_ident = img_conf.get('platform_ident') + if not platform_ident: + raise ValueError('invalid img_conf, missing \'platform_ident\'') + ident = platform_ident.get(self.platform_name) + if not ident: + raise ValueError('img_conf: {} missing config for platform {}' + .format(img_conf, self.platform_name)) + return ident + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/platforms/lxd.py b/tests/cloud_tests/platforms/lxd.py new file mode 100644 index 00000000..847cc549 --- /dev/null +++ b/tests/cloud_tests/platforms/lxd.py @@ -0,0 +1,97 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from pylxd import (Client, exceptions) + +from tests.cloud_tests.images import lxd as lxd_image +from tests.cloud_tests.instances import lxd as lxd_instance +from tests.cloud_tests.platforms import base +from tests.cloud_tests import util + +DEFAULT_SSTREAMS_SERVER = "https://images.linuxcontainers.org:8443" + + +class LXDPlatform(base.Platform): + """ + Lxd test platform + """ + platform_name = 'lxd' + + def __init__(self, config): + """ + Set up platform + """ + super(LXDPlatform, self).__init__(config) + # TODO: allow configuration of remote lxd host via env variables + # set up lxd connection + self.client = Client() + + def get_image(self, img_conf): + """ + Get image + img_conf: dict containing config for image. platform_ident must have: + alias: alias to use for simplestreams server + sstreams_server: simplestreams server to use, or None for default + return_value: cloud_tests.images instance + """ + lxd_conf = self._extract_img_platform_config(img_conf) + image = self.client.images.create_from_simplestreams( + lxd_conf.get('sstreams_server', DEFAULT_SSTREAMS_SERVER), + lxd_conf['alias']) + return lxd_image.LXDImage( + image.properties['description'], img_conf, self, image) + + def launch_container(self, image=None, container=None, ephemeral=False, + config=None, block=True, + image_desc=None, use_desc=None): + """ + launch a container + image: image fingerprint to launch from + container: container to copy + ephemeral: delete image after first shutdown + config: config options for instance as dict + block: wait until container created + image_desc: description of image being launched + use_desc: description of container's use + return_value: cloud_tests.instances instance + """ + if not (image or container): + raise ValueError("either image or container must be specified") + container = self.client.containers.create({ + 'name': util.gen_instance_name(image_desc=image_desc, + use_desc=use_desc, + used_list=self.list_containers()), + 'ephemeral': bool(ephemeral), + 'config': config if isinstance(config, dict) else {}, + 'source': ({'type': 'image', 'fingerprint': image} if image else + {'type': 'copy', 'source': container}) + }, wait=block) + return lxd_instance.LXDInstance(container.name, self, container) + + def container_exists(self, container_name): + """ + check if container with name 'container_name' exists + return_value: True if exists else False + """ + res = True + try: + self.client.containers.get(container_name) + except exceptions.LXDAPIException as e: + res = False + if e.response.status_code != 404: + raise + return res + + def list_containers(self): + """ + list names of all containers + return_value: list of names + """ + return [container.name for container in self.client.containers.all()] + + def destroy(self): + """ + Clean up platform data + """ + super(LXDPlatform, self).destroy() + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/releases.yaml b/tests/cloud_tests/releases.yaml new file mode 100644 index 00000000..3ffa68f0 --- /dev/null +++ b/tests/cloud_tests/releases.yaml @@ -0,0 +1,79 @@ +# ============================= Release Config ================================ +default_release_config: + # all are disabled by default + enabled: false + # timeout for booting image and running cloud init + timeout: 120 + # platform_ident values for the image, with data to identify the image + # on that platform. see platforms.base for more information + platform_ident: {} + # a script to run after a boot that is used to modify an image, before + # making a snapshot of the image. may be useful for removing data left + # behind from cloud-init booting, such as logs, to ensure that data from + # snapshot.launch() will not include a cloud-init.log from a boot used to + # create the snapshot, if cloud-init has not run + boot_clean_script: | + #!/bin/bash + rm -rf /var/log/cloud-init.log /var/log/cloud-init-output.log \ + /var/lib/cloud/ /run/cloud-init/ /var/log/syslog + +releases: + trusty: + enabled: true + platform_ident: + lxd: + # if sstreams_server is omitted, default is used, defined in + # tests.cloud_tests.platforms.lxd.DEFAULT_SSTREAMS_SERVER as: + # sstreams_server: https://us.images.linuxcontainers.org:8443 + #alias: ubuntu/trusty/default + alias: t + sstreams_server: https://cloud-images.ubuntu.com/daily + xenial: + enabled: true + platform_ident: + lxd: + #alias: ubuntu/xenial/default + alias: x + sstreams_server: https://cloud-images.ubuntu.com/daily + yakkety: + enabled: true + platform_ident: + lxd: + #alias: ubuntu/yakkety/default + alias: y + sstreams_server: https://cloud-images.ubuntu.com/daily + zesty: + enabled: true + platform_ident: + lxd: + #alias: ubuntu/zesty/default + alias: z + sstreams_server: https://cloud-images.ubuntu.com/daily + jessie: + platform_ident: + lxd: + alias: debian/jessie/default + sid: + platform_ident: + lxd: + alias: debian/sid/default + stretch: + platform_ident: + lxd: + alias: debian/stretch/default + wheezy: + platform_ident: + lxd: + alias: debian/wheezy/default + centos70: + timeout: 180 + platform_ident: + lxd: + alias: centos/7/default + centos66: + timeout: 180 + platform_ident: + lxd: + alias: centos/6/default + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/setup_image.py b/tests/cloud_tests/setup_image.py new file mode 100644 index 00000000..5d6c6387 --- /dev/null +++ b/tests/cloud_tests/setup_image.py @@ -0,0 +1,195 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from tests.cloud_tests import LOG +from tests.cloud_tests import stage, util + +from functools import partial +import os + + +def install_deb(args, image): + """ + install deb into image + args: cmdline arguments, must contain --deb + image: cloud_tests.images instance to operate on + return_value: None, may raise errors + """ + # ensure system is compatible with package format + os_family = util.get_os_family(image.properties['os']) + if os_family != 'debian': + raise NotImplementedError('install deb: {} not supported on os ' + 'family: {}'.format(args.deb, os_family)) + + # install deb + LOG.debug('installing deb: %s into target', args.deb) + remote_path = os.path.join('/tmp', os.path.basename(args.deb)) + image.push_file(args.deb, remote_path) + (out, err, exit) = image.execute(['dpkg', '-i', remote_path]) + if exit != 0: + raise OSError('failed install deb: {}\n\tstdout: {}\n\tstderr: {}' + .format(args.deb, out, err)) + + # check installed deb version matches package + fmt = ['-W', "--showformat='${Version}'"] + (out, err, exit) = image.execute(['dpkg-deb'] + fmt + [remote_path]) + expected_version = out.strip() + (out, err, exit) = image.execute(['dpkg-query'] + fmt + ['cloud-init']) + found_version = out.strip() + if expected_version != found_version: + raise OSError('install deb version "{}" does not match expected "{}"' + .format(found_version, expected_version)) + + LOG.debug('successfully installed: %s, version: %s', args.deb, + found_version) + + +def install_rpm(args, image): + """ + install rpm into image + args: cmdline arguments, must contain --rpm + image: cloud_tests.images instance to operate on + return_value: None, may raise errors + """ + # ensure system is compatible with package format + os_family = util.get_os_family(image.properties['os']) + if os_family not in ['redhat', 'sles']: + raise NotImplementedError('install rpm: {} not supported on os ' + 'family: {}'.format(args.rpm, os_family)) + + # install rpm + LOG.debug('installing rpm: %s into target', args.rpm) + remote_path = os.path.join('/tmp', os.path.basename(args.rpm)) + image.push_file(args.rpm, remote_path) + (out, err, exit) = image.execute(['rpm', '-U', remote_path]) + if exit != 0: + raise OSError('failed to install rpm: {}\n\tstdout: {}\n\tstderr: {}' + .format(args.rpm, out, err)) + + fmt = ['--queryformat', '"%{VERSION}"'] + (out, err, exit) = image.execute(['rpm', '-q'] + fmt + [remote_path]) + expected_version = out.strip() + (out, err, exit) = image.execute(['rpm', '-q'] + fmt + ['cloud-init']) + found_version = out.strip() + if expected_version != found_version: + raise OSError('install rpm version "{}" does not match expected "{}"' + .format(found_version, expected_version)) + + LOG.debug('successfully installed: %s, version %s', args.rpm, + found_version) + + +def upgrade(args, image): + """ + run the system's upgrade command + args: cmdline arguments + image: cloud_tests.images instance to operate on + return_value: None, may raise errors + """ + # determine appropriate upgrade command for os_family + # TODO: maybe use cloudinit.distros for this? + os_family = util.get_os_family(image.properties['os']) + if os_family == 'debian': + cmd = 'apt-get update && apt-get upgrade --yes' + elif os_family == 'redhat': + cmd = 'yum upgrade --assumeyes' + else: + raise NotImplementedError('upgrade command not configured for distro ' + 'from family: {}'.format(os_family)) + + # upgrade system + LOG.debug('upgrading system') + (out, err, exit) = image.execute(['/bin/sh', '-c', cmd]) + if exit != 0: + raise OSError('failed to upgrade system\n\tstdout: {}\n\tstderr:{}' + .format(out, err)) + + +def run_script(args, image): + """ + run a script in the target image + args: cmdline arguments, must contain --script + image: cloud_tests.images instance to operate on + return_value: None, may raise errors + """ + # TODO: get exit status back from script and add error handling here + LOG.debug('running setup image script in target image') + image.run_script(args.script) + + +def enable_ppa(args, image): + """ + enable a ppa in the target image + args: cmdline arguments, must contain --ppa + image: cloud_tests.image instance to operate on + return_value: None, may raise errors + """ + # ppa only supported on ubuntu (maybe debian?) + if image.properties['os'] != 'ubuntu': + raise NotImplementedError('enabling a ppa is only available on ubuntu') + + # add ppa with add-apt-repository and update + ppa = 'ppa:{}'.format(args.ppa) + LOG.debug('enabling %s', ppa) + cmd = 'add-apt-repository --yes {} && apt-get update'.format(ppa) + (out, err, exit) = image.execute(['/bin/sh', '-c', cmd]) + if exit != 0: + raise OSError('enable ppa for {} failed\n\tstdout: {}\n\tstderr: {}' + .format(ppa, out, err)) + + +def enable_repo(args, image): + """ + enable a repository in the target image + args: cmdline arguments, must contain --repo + image: cloud_tests.image instance to operate on + return_value: None, may raise errors + """ + # find enable repo command for the distro + os_family = util.get_os_family(image.properties['os']) + if os_family == 'debian': + cmd = ('echo "{}" >> "/etc/apt/sources.list" '.format(args.repo) + + '&& apt-get update') + elif os_family == 'centos': + cmd = 'yum-config-manager --add-repo="{}"'.format(args.repo) + else: + raise NotImplementedError('enable repo command not configured for ' + 'distro from family: {}'.format(os_family)) + + LOG.debug('enabling repo: "%s"', args.repo) + (out, err, exit) = image.execute(['/bin/sh', '-c', cmd]) + if exit != 0: + raise OSError('enable repo {} failed\n\tstdout: {}\n\tstderr: {}' + .format(args.repo, out, err)) + + +def setup_image(args, image): + """ + set up image as specified in args + args: cmdline arguments + image: cloud_tests.image instance to operate on + return_value: tuple of results and fail count + """ + # mapping of setup cmdline arg name to setup function + # represented as a tuple rather than a dict or odict as lookup by name not + # needed, and order is important as --script and --upgrade go at the end + handlers = ( + # arg handler description + ('deb', install_deb, 'setup func for --deb, install deb'), + ('rpm', install_rpm, 'setup func for --rpm, install rpm'), + ('repo', enable_repo, 'setup func for --repo, enable repo'), + ('ppa', enable_ppa, 'setup func for --ppa, enable ppa'), + ('script', run_script, 'setup func for --script, run script'), + ('upgrade', upgrade, 'setup func for --upgrade, upgrade pkgs'), + ) + + # determine which setup functions needed + calls = [partial(stage.run_single, desc, partial(func, args, image)) + for name, func, desc in handlers if getattr(args, name, None)] + + image_name = 'image: distro={}, release={}'.format( + image.properties['os'], image.properties['release']) + LOG.info('setting up %s', image_name) + return stage.run_stage('set up for {}'.format(image_name), calls, + continue_after_error=False) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/snapshots/__init__.py b/tests/cloud_tests/snapshots/__init__.py new file mode 100644 index 00000000..2ab654de --- /dev/null +++ b/tests/cloud_tests/snapshots/__init__.py @@ -0,0 +1,10 @@ +# This file is part of cloud-init. See LICENSE file for license information. + + +def get_snapshot(image): + """ + get snapshot from image + """ + return image.snapshot() + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/snapshots/base.py b/tests/cloud_tests/snapshots/base.py new file mode 100644 index 00000000..d715f037 --- /dev/null +++ b/tests/cloud_tests/snapshots/base.py @@ -0,0 +1,44 @@ +# This file is part of cloud-init. See LICENSE file for license information. + + +class Snapshot(object): + """ + Base class for snapshots + """ + platform_name = None + + def __init__(self, properties, config): + """ + Set up snapshot + """ + self.properties = properties + self.config = config + + def __str__(self): + """ + a brief description of the snapshot + """ + return '-'.join((self.properties['os'], self.properties['release'])) + + def launch(self, user_data, meta_data=None, block=True, start=True, + use_desc=None): + """ + launch instance + + user_data: user-data for the instance + instance_id: instance-id for the instance + block: wait until instance is created + start: start instance and wait until fully started + use_desc: description of snapshot instance use + + return_value: an Instance + """ + raise NotImplementedError + + def destroy(self): + """ + Clean up snapshot data + """ + pass + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/snapshots/lxd.py b/tests/cloud_tests/snapshots/lxd.py new file mode 100644 index 00000000..eabbce3f --- /dev/null +++ b/tests/cloud_tests/snapshots/lxd.py @@ -0,0 +1,50 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from tests.cloud_tests.snapshots import base + + +class LXDSnapshot(base.Snapshot): + """ + LXD image copy backed snapshot + """ + platform_name = "lxd" + + def __init__(self, properties, config, platform, pylxd_frozen_instance): + """ + Set up snapshot + """ + self.platform = platform + self.pylxd_frozen_instance = pylxd_frozen_instance + super(LXDSnapshot, self).__init__(properties, config) + + def launch(self, user_data, meta_data=None, block=True, start=True, + use_desc=None): + """ + launch instance + + user_data: user-data for the instance + instance_id: instance-id for the instance + block: wait until instance is created + start: start instance and wait until fully started + use_desc: description of snapshot instance use + + return_value: an Instance + """ + inst_config = {'user.user-data': user_data} + if meta_data: + inst_config['user.meta-data'] = meta_data + instance = self.platform.launch_container( + container=self.pylxd_frozen_instance.name, config=inst_config, + block=block, image_desc=str(self), use_desc=use_desc) + if start: + instance.start(wait=True, wait_time=self.config.get('timeout')) + return instance + + def destroy(self): + """ + Clean up snapshot data + """ + self.pylxd_frozen_instance.destroy() + super(LXDSnapshot, self).destroy() + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/stage.py b/tests/cloud_tests/stage.py new file mode 100644 index 00000000..584cdaee --- /dev/null +++ b/tests/cloud_tests/stage.py @@ -0,0 +1,113 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +import sys +import time +import traceback + +from tests.cloud_tests import LOG + + +class PlatformComponent(object): + """ + context manager to safely handle platform components, ensuring that + .destroy() is called + """ + + def __init__(self, get_func): + """ + store get_<platform component> function as partial taking no args + """ + self.get_func = get_func + + def __enter__(self): + """ + create instance of platform component + """ + self.instance = self.get_func() + return self.instance + + def __exit__(self, etype, value, trace): + """ + destroy instance + """ + if self.instance is not None: + self.instance.destroy() + + +def run_single(name, call): + """ + run a single function, keeping track of results and failures and time + name: name of part + call: call to make + return_value: a tuple of result and fail count + """ + res = { + 'name': name, + 'time': 0, + 'errors': [], + 'success': False + } + failed = 0 + start_time = time.time() + + try: + call() + except Exception as e: + failed += 1 + res['errors'].append(str(e)) + LOG.error('stage part: %s encountered error: %s', name, str(e)) + trace = traceback.extract_tb(sys.exc_info()[-1]) + LOG.error('traceback:\n%s', ''.join(traceback.format_list(trace))) + + res['time'] = time.time() - start_time + if failed == 0: + res['success'] = True + + return res, failed + + +def run_stage(parent_name, calls, continue_after_error=True): + """ + run a stage of collection, keeping track of results and failures + parent_name: name of stage calls are under + calls: list of function call taking no params. must return a tuple + of results and failures. may raise exceptions + continue_after_error: whether or not to proceed to the next call after + catching an exception or recording a failure + return_value: a tuple of results and failures, with result containing + results from the function call under 'stages', and a list + of errors (if any on this level), and elapsed time + running stage, and the name + """ + res = { + 'name': parent_name, + 'time': 0, + 'errors': [], + 'stages': [], + 'success': False, + } + failed = 0 + start_time = time.time() + + for call in calls: + try: + (call_res, call_failed) = call() + res['stages'].append(call_res) + except Exception as e: + call_failed = 1 + res['errors'].append(str(e)) + LOG.error('stage: %s encountered error: %s', parent_name, str(e)) + trace = traceback.extract_tb(sys.exc_info()[-1]) + LOG.error('traceback:\n%s', ''.join(traceback.format_list(trace))) + + failed += call_failed + if call_failed and not continue_after_error: + break + + res['time'] = time.time() - start_time + if not failed: + res['success'] = True + + return (res, failed) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases.yaml b/tests/cloud_tests/testcases.yaml new file mode 100644 index 00000000..c22b08ef --- /dev/null +++ b/tests/cloud_tests/testcases.yaml @@ -0,0 +1,27 @@ +# ============================= Base Test Config ============================== +base_test_data: + script_timeout: 20 + enabled: True + cloud_config: | + #cloud-config + collect_scripts: + cloud-init.log: | + #!/bin/bash + cat /var/log/cloud-init.log + cloud-init-output.log: | + #!/bin/bash + cat /var/log/cloud-init-output.log + instance-id: | + #!/bin/bash + cat /run/cloud-init/.instance-id + result.json: | + #!/bin/bash + cat /run/cloud-init/result.json + status.json: | + #!/bin/bash + cat /run/cloud-init/status.json + cloud-init-version: | + #!/bin/bash + dpkg-query -W -f='${Version}' cloud-init + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/__init__.py b/tests/cloud_tests/testcases/__init__.py new file mode 100644 index 00000000..182c090a --- /dev/null +++ b/tests/cloud_tests/testcases/__init__.py @@ -0,0 +1,47 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +import importlib +import inspect +import unittest + +from tests.cloud_tests import config +from tests.cloud_tests.testcases.base import CloudTestCase as base_test + + +def discover_tests(test_name): + """ + discover tests in test file for 'testname' + return_value: list of test classes + """ + testmod_name = 'tests.cloud_tests.testcases.{}'.format( + config.name_sanatize(test_name)) + try: + testmod = importlib.import_module(testmod_name) + except NameError: + raise ValueError('no test verifier found at: {}'.format(testmod_name)) + + return [mod for name, mod in inspect.getmembers(testmod) + if inspect.isclass(mod) and base_test in mod.__bases__ and + getattr(mod, '__test__', True)] + + +def get_suite(test_name, data, conf): + """ + get test suite with all tests for 'testname' + return_value: a test suite + """ + suite = unittest.TestSuite() + for test_class in discover_tests(test_name): + + class tmp(test_class): + + @classmethod + def setUpClass(cls): + cls.data = data + cls.conf = conf + + suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(tmp)) + + return suite + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/base.py b/tests/cloud_tests/testcases/base.py new file mode 100644 index 00000000..5395b9a3 --- /dev/null +++ b/tests/cloud_tests/testcases/base.py @@ -0,0 +1,81 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from cloudinit import util as c_util + +import json +import unittest + + +class CloudTestCase(unittest.TestCase): + """ + base test class for verifiers + """ + data = None + conf = None + _cloud_config = None + + @property + def cloud_config(self): + """ + get the cloud-config used by the test + """ + if not self._cloud_config: + self._cloud_config = c_util.load_yaml(self.conf) + return self._cloud_config + + def get_config_entry(self, name): + """ + get a config entry from cloud-config ensuring that it is present + """ + if name not in self.cloud_config: + raise AssertionError('Key "{}" not in cloud config'.format(name)) + return self.cloud_config[name] + + def get_data_file(self, name): + """ + get data file failing test if it is not present + """ + if name not in self.data: + raise AssertionError('File "{}" missing from collect data' + .format(name)) + return self.data[name] + + def get_instance_id(self): + """ + get recorded instance id + """ + return self.get_data_file('instance-id').strip() + + def get_status_data(self, data, version=None): + """ + parse result.json and status.json like data files + data: data to load + version: cloud-init output version, defaults to 'v1' + return_value: dict of data or None if missing + """ + if not version: + version = 'v1' + data = json.loads(data) + return data.get(version) + + def get_datasource(self): + """ + get datasource name + """ + data = self.get_status_data(self.get_data_file('result.json')) + return data.get('datasource') + + def test_no_stages_errors(self): + """ + ensure that there were no errors in any stage + """ + status = self.get_status_data(self.get_data_file('status.json')) + for stage in ('init', 'init-local', 'modules-config', 'modules-final'): + self.assertIn(stage, status) + self.assertEqual(len(status[stage]['errors']), 0, + 'errors {} were encountered in stage {}' + .format(status[stage]['errors'], stage)) + result = self.get_status_data(self.get_data_file('result.json')) + self.assertEqual(len(result['errors']), 0) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/bugs/__init__.py b/tests/cloud_tests/testcases/bugs/__init__.py new file mode 100644 index 00000000..5251d7c1 --- /dev/null +++ b/tests/cloud_tests/testcases/bugs/__init__.py @@ -0,0 +1,8 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +""" +Test verifiers for cloud-init bugs +See configs/bugs/README.md for more information +""" + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/bugs/lp1511485.py b/tests/cloud_tests/testcases/bugs/lp1511485.py new file mode 100644 index 00000000..ac5ccb42 --- /dev/null +++ b/tests/cloud_tests/testcases/bugs/lp1511485.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestLP1511485(base.CloudTestCase): + """Test LP# 1511485""" + + def test_final_message(self): + """Test final message exists""" + out = self.get_data_file('cloud-init-output.log') + self.assertIn('Final message from cloud-config', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/bugs/lp1628337.py b/tests/cloud_tests/testcases/bugs/lp1628337.py new file mode 100644 index 00000000..af0ffc75 --- /dev/null +++ b/tests/cloud_tests/testcases/bugs/lp1628337.py @@ -0,0 +1,23 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestLP1628337(base.CloudTestCase): + """Test LP# 1511485""" + + def test_fetch_indices(self): + """Verify no apt errors""" + out = self.get_data_file('cloud-init-output.log') + self.assertNotIn('W: Failed to fetch', out) + self.assertNotIn('W: Some index files failed to download. ' + 'They have been ignored, or old ones used instead.', + out) + + def test_ntp(self): + """Verify can find ntp and install it""" + out = self.get_data_file('cloud-init-output.log') + self.assertNotIn('E: Unable to locate package ntp', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/examples/__init__.py b/tests/cloud_tests/testcases/examples/__init__.py new file mode 100644 index 00000000..b3af7f8a --- /dev/null +++ b/tests/cloud_tests/testcases/examples/__init__.py @@ -0,0 +1,8 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +""" +Test verifiers for cloud-init examples +See configs/examples/README.md for more information +""" + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/examples/add_apt_repositories.py b/tests/cloud_tests/testcases/examples/add_apt_repositories.py new file mode 100644 index 00000000..15b8f01c --- /dev/null +++ b/tests/cloud_tests/testcases/examples/add_apt_repositories.py @@ -0,0 +1,20 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptconfigurePrimary(base.CloudTestCase): + """Example cloud-config test""" + + def test_ubuntu_sources(self): + """Test no default Ubuntu entries exist""" + out = self.get_data_file('ubuntu.sources.list') + self.assertEqual(0, int(out)) + + def test_gatech_sources(self): + """Test GaTech entires exist""" + out = self.get_data_file('gatech.sources.list') + self.assertEqual(20, int(out)) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/examples/alter_completion_message.py b/tests/cloud_tests/testcases/examples/alter_completion_message.py new file mode 100644 index 00000000..b06ad01b --- /dev/null +++ b/tests/cloud_tests/testcases/examples/alter_completion_message.py @@ -0,0 +1,49 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestFinalMessage(base.CloudTestCase): + """ + test cloud init module `cc_final_message` + """ + subs_char = '$' + + def get_final_message_config(self): + """ + get config for final message + """ + self.assertIn('final_message', self.cloud_config) + return self.cloud_config['final_message'] + + def get_final_message(self): + """ + get final message from log + """ + out = self.get_data_file('cloud-init-output.log') + lines = len(self.get_final_message_config().splitlines()) + return '\n'.join(out.splitlines()[-1 * lines:]) + + def test_final_message_string(self): + """ + ensure final handles regular strings + """ + for actual, config in zip( + self.get_final_message().splitlines(), + self.get_final_message_config().splitlines()): + if self.subs_char not in config: + self.assertEqual(actual, config) + + def test_final_message_subs(self): + """ + test variable substitution in final message + """ + # TODO: add verification of other substitutions + patterns = {'$datasource': self.get_datasource()} + for key, expected in patterns.items(): + index = self.get_final_message_config().splitlines().index(key) + actual = self.get_final_message().splitlines()[index] + self.assertEqual(actual, expected) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.py b/tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.py new file mode 100644 index 00000000..8a4a0db0 --- /dev/null +++ b/tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.py @@ -0,0 +1,27 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestTrustedCA(base.CloudTestCase): + """Example cloud-config test""" + + def test_cert_count_ca(self): + """Test correct count of CAs in .crt""" + out = self.get_data_file('cert_count_ca') + self.assertIn('7 /etc/ssl/certs/ca-certificates.crt', out) + + def test_cert_count_cloudinit(self): + """Test correct count of CAs in .pem""" + out = self.get_data_file('cert_count_cloudinit') + self.assertIn('7 /etc/ssl/certs/cloud-init-ca-certs.pem', out) + + def test_cloudinit_certs(self): + """Test text of cert""" + out = self.get_data_file('cloudinit_certs') + self.assertIn('-----BEGIN CERTIFICATE-----', out) + self.assertIn('YOUR-ORGS-TRUSTED-CA-CERT-HERE', out) + self.assertIn('-----END CERTIFICATE-----', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/examples/configure_instances_ssh_keys.py b/tests/cloud_tests/testcases/examples/configure_instances_ssh_keys.py new file mode 100644 index 00000000..4f651703 --- /dev/null +++ b/tests/cloud_tests/testcases/examples/configure_instances_ssh_keys.py @@ -0,0 +1,31 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestSSHKeys(base.CloudTestCase): + """Example cloud-config test""" + + def test_cert_count(self): + """Test cert count""" + out = self.get_data_file('cert_count') + self.assertEqual(20, int(out)) + + def test_dsa_public(self): + """Test DSA key has ending""" + out = self.get_data_file('dsa_public') + self.assertIn('ZN4XnifuO5krqAybngIy66PMEoQ= smoser@localhost', out) + + def test_rsa_public(self): + """Test RSA key has specific ending""" + out = self.get_data_file('rsa_public') + self.assertIn('PemAWthxHO18QJvWPocKJtlsDNi3 smoser@localhost', out) + + def test_auth_keys(self): + """Test authorized keys has specific ending""" + out = self.get_data_file('auth_keys') + self.assertIn('QPOt5Q8zWd9qG7PBl9+eiH5qV7NZ mykey@host', out) + self.assertIn('Hj29SCmXp5Kt5/82cD/VN3NtHw== smoser@brickies', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/examples/including_user_groups.py b/tests/cloud_tests/testcases/examples/including_user_groups.py new file mode 100644 index 00000000..e5732322 --- /dev/null +++ b/tests/cloud_tests/testcases/examples/including_user_groups.py @@ -0,0 +1,43 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestUserGroups(base.CloudTestCase): + """Example cloud-config test""" + + def test_group_ubuntu(self): + """Test ubuntu group exists""" + out = self.get_data_file('group_ubuntu') + self.assertRegex(out, r'ubuntu:x:[0-9]{4}:') + + def test_group_cloud_users(self): + """Test cloud users group exists""" + out = self.get_data_file('group_cloud_users') + self.assertRegex(out, r'cloud-users:x:[0-9]{4}:barfoo') + + def test_user_ubuntu(self): + """Test ubuntu user exists""" + out = self.get_data_file('user_ubuntu') + self.assertRegex( + out, r'ubuntu:x:[0-9]{4}:[0-9]{4}:Ubuntu:/home/ubuntu:/bin/bash') + + def test_user_foobar(self): + """Test foobar user exists""" + out = self.get_data_file('user_foobar') + self.assertRegex( + out, r'foobar:x:[0-9]{4}:[0-9]{4}:Foo B. Bar:/home/foobar:') + + def test_user_barfoo(self): + """Test barfoo user exists""" + out = self.get_data_file('user_barfoo') + self.assertRegex( + out, r'barfoo:x:[0-9]{4}:[0-9]{4}:Bar B. Foo:/home/barfoo:') + + def test_user_cloudy(self): + """Test cloudy user exists""" + out = self.get_data_file('user_cloudy') + self.assertRegex(out, r'cloudy:x:[0-9]{3,4}:') + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/examples/install_arbitrary_packages.py b/tests/cloud_tests/testcases/examples/install_arbitrary_packages.py new file mode 100644 index 00000000..660d1aa3 --- /dev/null +++ b/tests/cloud_tests/testcases/examples/install_arbitrary_packages.py @@ -0,0 +1,20 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestInstall(base.CloudTestCase): + """Example cloud-config test""" + + def test_htop(self): + """Verify htop installed""" + out = self.get_data_file('htop') + self.assertEqual(1, int(out)) + + def test_tree(self): + """Verify tree installed""" + out = self.get_data_file('treeutils') + self.assertEqual(1, int(out)) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/examples/run_apt_upgrade.py b/tests/cloud_tests/testcases/examples/run_apt_upgrade.py new file mode 100644 index 00000000..4c04d315 --- /dev/null +++ b/tests/cloud_tests/testcases/examples/run_apt_upgrade.py @@ -0,0 +1,19 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestUpgrade(base.CloudTestCase): + """Example cloud-config test""" + + def test_upgrade(self): + """Test upgrade exists in apt history""" + out = self.get_data_file('cloud-init.log') + self.assertIn( + '[CLOUDINIT] util.py[DEBUG]: apt-upgrade ' + '[eatmydata apt-get --option=Dpkg::Options::=--force-confold ' + '--option=Dpkg::options::=--force-unsafe-io --assume-yes --quiet ' + 'dist-upgrade] took', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/examples/run_commands.py b/tests/cloud_tests/testcases/examples/run_commands.py new file mode 100644 index 00000000..0be21d0f --- /dev/null +++ b/tests/cloud_tests/testcases/examples/run_commands.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestRunCmd(base.CloudTestCase): + """Example cloud-config test""" + + def test_run_cmd(self): + """Test run command worked""" + out = self.get_data_file('run_cmd') + self.assertIn('cloud-init run cmd test', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/examples/run_commands_first_boot.py b/tests/cloud_tests/testcases/examples/run_commands_first_boot.py new file mode 100644 index 00000000..baa23130 --- /dev/null +++ b/tests/cloud_tests/testcases/examples/run_commands_first_boot.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestBootCmd(base.CloudTestCase): + """Example cloud-config test""" + + def test_bootcmd_host(self): + """Test boot command worked""" + out = self.get_data_file('hosts') + self.assertIn('192.168.1.130 us.archive.ubuntu.com', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/examples/writing_out_arbitrary_files.py b/tests/cloud_tests/testcases/examples/writing_out_arbitrary_files.py new file mode 100644 index 00000000..97dfeec3 --- /dev/null +++ b/tests/cloud_tests/testcases/examples/writing_out_arbitrary_files.py @@ -0,0 +1,30 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestWriteFiles(base.CloudTestCase): + """Example cloud-config test""" + + def test_b64(self): + """Test b64 encoded file reads as ascii""" + out = self.get_data_file('file_b64') + self.assertIn('ASCII text', out) + + def test_binary(self): + """Test binary file reads as executable""" + out = self.get_data_file('file_binary') + self.assertIn('ELF 64-bit LSB executable, x86-64, version 1', out) + + def test_gzip(self): + """Test gzip file shows up as a shell script""" + out = self.get_data_file('file_gzip') + self.assertIn('POSIX shell script, ASCII text executable', out) + + def test_text(self): + """Test text shows up as ASCII text""" + out = self.get_data_file('file_text') + self.assertIn('ASCII text', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/main/__init__.py b/tests/cloud_tests/testcases/main/__init__.py new file mode 100644 index 00000000..5888990d --- /dev/null +++ b/tests/cloud_tests/testcases/main/__init__.py @@ -0,0 +1,8 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +""" +Test verifiers for cloud-init main features +See configs/main/README.md for more information +""" + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/main/command_output_simple.py b/tests/cloud_tests/testcases/main/command_output_simple.py new file mode 100644 index 00000000..c0461a08 --- /dev/null +++ b/tests/cloud_tests/testcases/main/command_output_simple.py @@ -0,0 +1,21 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from tests.cloud_tests.testcases import base + + +class TestCommandOutputSimple(base.CloudTestCase): + """ + test functionality of simple output redirection + """ + + def test_output_file(self): + """ + ensure that the output file is not empty and has all stages + """ + data = self.get_data_file('cloud-init-test-output') + self.assertNotEqual(len(data), 0, "specified log empty") + self.assertEqual(self.get_config_entry('final_message'), + data.splitlines()[-1].strip()) + # TODO: need to test that all stages redirected here + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/__init__.py b/tests/cloud_tests/testcases/modules/__init__.py new file mode 100644 index 00000000..9560fb26 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/__init__.py @@ -0,0 +1,8 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +""" +Test verifiers for cloud-init cc modules +See configs/modules/README.md for more information +""" + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/apt_configure_conf.py b/tests/cloud_tests/testcases/modules/apt_configure_conf.py new file mode 100644 index 00000000..5d96d95c --- /dev/null +++ b/tests/cloud_tests/testcases/modules/apt_configure_conf.py @@ -0,0 +1,20 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptconfigureConf(base.CloudTestCase): + """Test apt-configure module""" + + def test_apt_conf_assumeyes(self): + """Test config assumes true""" + out = self.get_data_file('94cloud-init-config') + self.assertIn('Assume-Yes "true";', out) + + def test_apt_conf_fixbroken(self): + """Test config fixes broken""" + out = self.get_data_file('94cloud-init-config') + self.assertIn('Fix-Broken "true";', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/apt_configure_disable_suites.py b/tests/cloud_tests/testcases/modules/apt_configure_disable_suites.py new file mode 100644 index 00000000..0e2dfdeb --- /dev/null +++ b/tests/cloud_tests/testcases/modules/apt_configure_disable_suites.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptconfigureDisableSuites(base.CloudTestCase): + """Test apt-configure module""" + + def test_empty_sourcelist(self): + """Test source list is empty""" + out = self.get_data_file('sources.list') + self.assertEqual('', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/apt_configure_primary.py b/tests/cloud_tests/testcases/modules/apt_configure_primary.py new file mode 100644 index 00000000..2918785d --- /dev/null +++ b/tests/cloud_tests/testcases/modules/apt_configure_primary.py @@ -0,0 +1,20 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptconfigurePrimary(base.CloudTestCase): + """Test apt-configure module""" + + def test_ubuntu_sources(self): + """Test no default Ubuntu entries exist""" + out = self.get_data_file('ubuntu.sources.list') + self.assertEqual(0, int(out)) + + def test_gatech_sources(self): + """Test GaTech entires exist""" + out = self.get_data_file('gatech.sources.list') + self.assertEqual(20, int(out)) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/apt_configure_proxy.py b/tests/cloud_tests/testcases/modules/apt_configure_proxy.py new file mode 100644 index 00000000..93ae64c6 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/apt_configure_proxy.py @@ -0,0 +1,22 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptconfigureProxy(base.CloudTestCase): + """Test apt-configure module""" + + def test_proxy_config(self): + """Test proxy options added to apt config""" + out = self.get_data_file('90cloud-init-aptproxy') + self.assertIn( + 'Acquire::http::Proxy "http://squid.internal:3128";', out) + self.assertIn( + 'Acquire::http::Proxy "http://squid.internal:3128";', out) + self.assertIn( + 'Acquire::ftp::Proxy "ftp://squid.internal:3128";', out) + self.assertIn( + 'Acquire::https::Proxy "https://squid.internal:3128";', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/apt_configure_security.py b/tests/cloud_tests/testcases/modules/apt_configure_security.py new file mode 100644 index 00000000..19c79c64 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/apt_configure_security.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptconfigureSecurity(base.CloudTestCase): + """Test apt-configure module""" + + def test_security_mirror(self): + """Test security lines added and uncommented in source.list""" + out = self.get_data_file('sources.list') + self.assertEqual(6, int(out)) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_key.py b/tests/cloud_tests/testcases/modules/apt_configure_sources_key.py new file mode 100644 index 00000000..d2ee2611 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/apt_configure_sources_key.py @@ -0,0 +1,23 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptconfigureSourcesKey(base.CloudTestCase): + """Test apt-configure module""" + + def test_apt_key_list(self): + """Test key list updated""" + out = self.get_data_file('apt_key_list') + self.assertIn( + '1FF0 D853 5EF7 E719 E5C8 1B9C 083D 06FB E4D3 04DF', out) + self.assertIn('Launchpad PPA for cloud init development team', out) + + def test_source_list(self): + """Test source.list updated""" + out = self.get_data_file('sources.list') + self.assertIn( + 'http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.py b/tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.py new file mode 100644 index 00000000..3931a92c --- /dev/null +++ b/tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.py @@ -0,0 +1,23 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptconfigureSourcesKeyserver(base.CloudTestCase): + """Test apt-configure module""" + + def test_apt_key_list(self): + """Test specific key added""" + out = self.get_data_file('apt_key_list') + self.assertIn( + '1BC3 0F71 5A3B 8612 47A8 1A5E 55FE 7C8C 0165 013E', out) + self.assertIn('Launchpad PPA for curtin developers', out) + + def test_source_list(self): + """Test source.list updated""" + out = self.get_data_file('sources.list') + self.assertIn( + 'http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_list.py b/tests/cloud_tests/testcases/modules/apt_configure_sources_list.py new file mode 100644 index 00000000..a0bb5e6b --- /dev/null +++ b/tests/cloud_tests/testcases/modules/apt_configure_sources_list.py @@ -0,0 +1,26 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptconfigureSourcesList(base.CloudTestCase): + """Test apt-configure module""" + + def test_sources_list(self): + """Test sources.list includes sources""" + out = self.get_data_file('sources.list') + self.assertRegex(out, r'deb http:\/\/archive.ubuntu.com\/ubuntu ' + '[a-z].* main restricted') + self.assertRegex(out, r'deb-src http:\/\/archive.ubuntu.com\/ubuntu ' + '[a-z].* main restricted') + self.assertRegex(out, r'deb http:\/\/archive.ubuntu.com\/ubuntu ' + '[a-z].* universe restricted') + self.assertRegex(out, r'deb-src http:\/\/archive.ubuntu.com\/ubuntu ' + '[a-z].* universe restricted') + self.assertRegex(out, r'deb http:\/\/security.ubuntu.com\/ubuntu ' + '[a-z].*security multiverse') + self.assertRegex(out, r'deb-src http:\/\/security.ubuntu.com\/ubuntu ' + '[a-z].*security multiverse') + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.py b/tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.py new file mode 100644 index 00000000..dcdb3767 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.py @@ -0,0 +1,23 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptconfigureSourcesPPA(base.CloudTestCase): + """Test apt-configure module""" + + def test_ppa(self): + """test specific ppa added""" + out = self.get_data_file('sources.list') + self.assertIn( + 'http://ppa.launchpad.net/curtin-dev/test-archive/ubuntu', out) + + def test_ppa_key(self): + """test ppa key added""" + out = self.get_data_file('apt-key') + self.assertIn( + '1BC3 0F71 5A3B 8612 47A8 1A5E 55FE 7C8C 0165 013E', out) + self.assertIn('Launchpad PPA for curtin developers', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/apt_pipelining_disable.py b/tests/cloud_tests/testcases/modules/apt_pipelining_disable.py new file mode 100644 index 00000000..446c597d --- /dev/null +++ b/tests/cloud_tests/testcases/modules/apt_pipelining_disable.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptPipeliningDisable(base.CloudTestCase): + """Test apt-pipelining module""" + + def test_disable_pipelining(self): + """Test pipelining disabled""" + out = self.get_data_file('90cloud-init-pipelining') + self.assertIn('Acquire::http::Pipeline-Depth "0";', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/apt_pipelining_os.py b/tests/cloud_tests/testcases/modules/apt_pipelining_os.py new file mode 100644 index 00000000..ad2a8884 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/apt_pipelining_os.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestAptPipeliningOS(base.CloudTestCase): + """Test apt-pipelining module""" + + def test_os_pipelining(self): + """Test pipelining set to os""" + out = self.get_data_file('90cloud-init-pipelining') + self.assertIn('Acquire::http::Pipeline-Depth "0";', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/bootcmd.py b/tests/cloud_tests/testcases/modules/bootcmd.py new file mode 100644 index 00000000..47a51e0a --- /dev/null +++ b/tests/cloud_tests/testcases/modules/bootcmd.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestBootCmd(base.CloudTestCase): + """Test bootcmd module""" + + def test_bootcmd_host(self): + """Test boot cmd worked""" + out = self.get_data_file('hosts') + self.assertIn('192.168.1.130 us.archive.ubuntu.com', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/byobu.py b/tests/cloud_tests/testcases/modules/byobu.py new file mode 100644 index 00000000..204b37b9 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/byobu.py @@ -0,0 +1,25 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestByobu(base.CloudTestCase): + """Test Byobu module""" + + def test_byobu_installed(self): + """Test byobu installed""" + out = self.get_data_file('byobu_installed') + self.assertIn('/usr/bin/byobu', out) + + def test_byobu_profile_enabled(self): + """Test byobu profile.d file exists""" + out = self.get_data_file('byobu_profile_enabled') + self.assertIn('/etc/profile.d/Z97-byobu.sh', out) + + def test_byobu_launch_exists(self): + """Test byobu-launch exists""" + out = self.get_data_file('byobu_launch_exists') + self.assertIn('/usr/bin/byobu-launch', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/ca_certs.py b/tests/cloud_tests/testcases/modules/ca_certs.py new file mode 100644 index 00000000..7448e480 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/ca_certs.py @@ -0,0 +1,20 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestCaCerts(base.CloudTestCase): + """Test ca certs module""" + + def test_cert_count(self): + """Test the count is proper""" + out = self.get_data_file('cert_count') + self.assertEqual(5, int(out)) + + def test_cert_installed(self): + """Test line from our cert exists""" + out = self.get_data_file('cert') + self.assertIn('a36c744454555024e7f82edc420fd2c8', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/debug_disable.py b/tests/cloud_tests/testcases/modules/debug_disable.py new file mode 100644 index 00000000..9899fdfe --- /dev/null +++ b/tests/cloud_tests/testcases/modules/debug_disable.py @@ -0,0 +1,16 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestDebugDisable(base.CloudTestCase): + """Disable debug messages""" + + def test_debug_disable(self): + """Test verbose output missing from logs""" + out = self.get_data_file('cloud-init.log') + self.assertNotIn( + out, r'Skipping module named [a-z].* verbose printing disabled') + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/debug_enable.py b/tests/cloud_tests/testcases/modules/debug_enable.py new file mode 100644 index 00000000..21c89524 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/debug_enable.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestDebugEnable(base.CloudTestCase): + """Test debug messages""" + + def test_debug_enable(self): + """Test debug messages in cloud-init log""" + out = self.get_data_file('cloud-init.log') + self.assertIn('[DEBUG]', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/final_message.py b/tests/cloud_tests/testcases/modules/final_message.py new file mode 100644 index 00000000..b06ad01b --- /dev/null +++ b/tests/cloud_tests/testcases/modules/final_message.py @@ -0,0 +1,49 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestFinalMessage(base.CloudTestCase): + """ + test cloud init module `cc_final_message` + """ + subs_char = '$' + + def get_final_message_config(self): + """ + get config for final message + """ + self.assertIn('final_message', self.cloud_config) + return self.cloud_config['final_message'] + + def get_final_message(self): + """ + get final message from log + """ + out = self.get_data_file('cloud-init-output.log') + lines = len(self.get_final_message_config().splitlines()) + return '\n'.join(out.splitlines()[-1 * lines:]) + + def test_final_message_string(self): + """ + ensure final handles regular strings + """ + for actual, config in zip( + self.get_final_message().splitlines(), + self.get_final_message_config().splitlines()): + if self.subs_char not in config: + self.assertEqual(actual, config) + + def test_final_message_subs(self): + """ + test variable substitution in final message + """ + # TODO: add verification of other substitutions + patterns = {'$datasource': self.get_datasource()} + for key, expected in patterns.items(): + index = self.get_final_message_config().splitlines().index(key) + actual = self.get_final_message().splitlines()[index] + self.assertEqual(actual, expected) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/keys_to_console.py b/tests/cloud_tests/testcases/modules/keys_to_console.py new file mode 100644 index 00000000..b36c96cf --- /dev/null +++ b/tests/cloud_tests/testcases/modules/keys_to_console.py @@ -0,0 +1,22 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestKeysToConsole(base.CloudTestCase): + """Test proper keys are included and excluded to console""" + + def test_excluded_keys(self): + """Test excluded keys missing""" + out = self.get_data_file('syslog') + self.assertNotIn('DSA', out) + self.assertNotIn('ECDSA', out) + + def test_expected_keys(self): + """Test expected keys exist""" + out = self.get_data_file('syslog') + self.assertIn('ED25519', out) + self.assertIn('RSA', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/locale.py b/tests/cloud_tests/testcases/modules/locale.py new file mode 100644 index 00000000..bf4e1b07 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/locale.py @@ -0,0 +1,27 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestLocale(base.CloudTestCase): + """Test locale is set properly""" + + def test_locale(self): + """Test locale is set properly""" + out = self.get_data_file('locale_default') + self.assertIn('LANG="en_GB.UTF-8"', out) + + def test_locale_a(self): + """Test locale -a has both options""" + out = self.get_data_file('locale_a') + self.assertIn('en_GB.utf8', out) + self.assertIn('en_US.utf8', out) + + def test_locale_gen(self): + """Test local.gen file has all entries.""" + out = self.get_data_file('locale_gen') + self.assertIn('en_GB.UTF-8', out) + self.assertIn('en_US.UTF-8', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/lxd_bridge.py b/tests/cloud_tests/testcases/modules/lxd_bridge.py new file mode 100644 index 00000000..4087e2f2 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/lxd_bridge.py @@ -0,0 +1,26 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestLxdBridge(base.CloudTestCase): + """Test LXD module""" + + def test_lxd(self): + """Test lxd installed""" + out = self.get_data_file('lxd') + self.assertIn('/usr/bin/lxd', out) + + def test_lxc(self): + """Test lxc installed""" + out = self.get_data_file('lxc') + self.assertIn('/usr/bin/lxc', out) + + def test_bridge(self): + """Test bridge config""" + out = self.get_data_file('lxc-bridge') + self.assertIn('lxdbr0', out) + self.assertIn('10.100.100.1/24', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/lxd_dir.py b/tests/cloud_tests/testcases/modules/lxd_dir.py new file mode 100644 index 00000000..51a9a1f1 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/lxd_dir.py @@ -0,0 +1,20 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestLxdDir(base.CloudTestCase): + """Test LXD module""" + + def test_lxd(self): + """Test lxd installed""" + out = self.get_data_file('lxd') + self.assertIn('/usr/bin/lxd', out) + + def test_lxc(self): + """Test lxc installed""" + out = self.get_data_file('lxc') + self.assertIn('/usr/bin/lxc', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/ntp.py b/tests/cloud_tests/testcases/modules/ntp.py new file mode 100644 index 00000000..b1119257 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/ntp.py @@ -0,0 +1,28 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestNtp(base.CloudTestCase): + """Test ntp module""" + + def test_ntp_installed(self): + """Test ntp installed""" + out = self.get_data_file('ntp_installed_empty') + self.assertEqual(1, int(out)) + + def test_ntp_dist_entries(self): + """Test dist config file has one entry""" + out = self.get_data_file('ntp_conf_dist_empty') + self.assertEqual(1, int(out)) + + def test_ntp_entires(self): + """Test config entries""" + out = self.get_data_file('ntp_conf_empty') + self.assertIn('pool 0.ubuntu.pool.ntp.org iburst', out) + self.assertIn('pool 1.ubuntu.pool.ntp.org iburst', out) + self.assertIn('pool 2.ubuntu.pool.ntp.org iburst', out) + self.assertIn('pool 3.ubuntu.pool.ntp.org iburst', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/ntp_pools.py b/tests/cloud_tests/testcases/modules/ntp_pools.py new file mode 100644 index 00000000..d80cb673 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/ntp_pools.py @@ -0,0 +1,28 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestNtpPools(base.CloudTestCase): + """Test ntp module""" + + def test_ntp_installed(self): + """Test ntp installed""" + out = self.get_data_file('ntp_installed_pools') + self.assertEqual(1, int(out)) + + def test_ntp_dist_entries(self): + """Test dist config file has one entry""" + out = self.get_data_file('ntp_conf_dist_pools') + self.assertEqual(1, int(out)) + + def test_ntp_entires(self): + """Test config entries""" + out = self.get_data_file('ntp_conf_pools') + self.assertIn('pool 0.pool.ntp.org iburst', out) + self.assertIn('pool 1.pool.ntp.org iburst', out) + self.assertIn('pool 2.pool.ntp.org iburst', out) + self.assertIn('pool 3.pool.ntp.org iburst', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/ntp_servers.py b/tests/cloud_tests/testcases/modules/ntp_servers.py new file mode 100644 index 00000000..4879bb6f --- /dev/null +++ b/tests/cloud_tests/testcases/modules/ntp_servers.py @@ -0,0 +1,25 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestNtpServers(base.CloudTestCase): + """Test ntp module""" + + def test_ntp_installed(self): + """Test ntp installed""" + out = self.get_data_file('ntp_installed_servers') + self.assertEqual(1, int(out)) + + def test_ntp_dist_entries(self): + """Test dist config file has one entry""" + out = self.get_data_file('ntp_conf_dist_servers') + self.assertEqual(1, int(out)) + + def test_ntp_entires(self): + """Test config entries""" + out = self.get_data_file('ntp_conf_servers') + self.assertIn('server pool.ntp.org iburst', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/package_update_upgrade_install.py b/tests/cloud_tests/testcases/modules/package_update_upgrade_install.py new file mode 100644 index 00000000..00353ead --- /dev/null +++ b/tests/cloud_tests/testcases/modules/package_update_upgrade_install.py @@ -0,0 +1,38 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestPackageInstallUpdateUpgrade(base.CloudTestCase): + """Test package install update upgrade module""" + + def test_installed_htop(self): + """Test htop got installed""" + out = self.get_data_file('dpkg_htop') + self.assertEqual(1, int(out)) + + def test_installed_tree(self): + """Test tree got installed""" + out = self.get_data_file('dpkg_tree') + self.assertEqual(1, int(out)) + + def test_apt_history(self): + """Test apt history for update command""" + out = self.get_data_file('apt_history_cmdline') + self.assertIn( + 'Commandline: /usr/bin/apt-get --option=Dpkg::Options' + '::=--force-confold --option=Dpkg::options::=--force-unsafe-io ' + '--assume-yes --quiet install htop tree', out) + + def test_cloud_init_output(self): + """Test cloud-init-output for install & upgrade stuff""" + out = self.get_data_file('cloud-init-output.log') + self.assertIn('Setting up tree (', out) + self.assertIn('Setting up htop (', out) + self.assertIn('Reading package lists...', out) + self.assertIn('Building dependency tree...', out) + self.assertIn('Reading state information...', out) + self.assertIn('Calculating upgrade...', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/runcmd.py b/tests/cloud_tests/testcases/modules/runcmd.py new file mode 100644 index 00000000..780cd186 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/runcmd.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestRunCmd(base.CloudTestCase): + """Test runcmd module""" + + def test_run_cmd(self): + """Test run command worked""" + out = self.get_data_file('run_cmd') + self.assertIn('cloud-init run cmd test', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/salt_minion.py b/tests/cloud_tests/testcases/modules/salt_minion.py new file mode 100644 index 00000000..3ef30f7e --- /dev/null +++ b/tests/cloud_tests/testcases/modules/salt_minion.py @@ -0,0 +1,29 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class Test(base.CloudTestCase): + """Test salt minion module""" + + def test_minon_master(self): + """Test master value in config""" + out = self.get_data_file('minion') + self.assertIn('master: salt.mydomain.com', out) + + def test_minion_pem(self): + """Test private key""" + out = self.get_data_file('minion.pem') + self.assertIn('------BEGIN PRIVATE KEY------', out) + self.assertIn('<key data>', out) + self.assertIn('------END PRIVATE KEY-------', out) + + def test_minion_pub(self): + """Test public key""" + out = self.get_data_file('minion.pub') + self.assertIn('------BEGIN PUBLIC KEY-------', out) + self.assertIn('<key data>', out) + self.assertIn('------END PUBLIC KEY-------', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/seed_random_data.py b/tests/cloud_tests/testcases/modules/seed_random_data.py new file mode 100644 index 00000000..b2121569 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/seed_random_data.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestSeedRandom(base.CloudTestCase): + """Test seed random module""" + + def test_random_seed_data(self): + """Test random data passed in exists""" + out = self.get_data_file('seed_data') + self.assertIn('MYUb34023nD:LFDK10913jk;dfnk:Df', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/set_hostname.py b/tests/cloud_tests/testcases/modules/set_hostname.py new file mode 100644 index 00000000..9501b069 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/set_hostname.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestHostname(base.CloudTestCase): + """Test hostname module""" + + def test_hostname(self): + """Test hostname command shows correct output""" + out = self.get_data_file('hostname') + self.assertIn('myhostname', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/set_hostname_fqdn.py b/tests/cloud_tests/testcases/modules/set_hostname_fqdn.py new file mode 100644 index 00000000..d89c299d --- /dev/null +++ b/tests/cloud_tests/testcases/modules/set_hostname_fqdn.py @@ -0,0 +1,26 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestHostnameFqdn(base.CloudTestCase): + """Test Hostname module""" + + def test_hostname(self): + """Test hostname output""" + out = self.get_data_file('hostname') + self.assertIn('myhostname', out) + + def test_hostname_fqdn(self): + """Test hostname fqdn output""" + out = self.get_data_file('fqdn') + self.assertIn('host.myorg.com', out) + + def test_hosts(self): + """Test /etc/hosts file""" + out = self.get_data_file('hosts') + self.assertIn('127.0.1.1 host.myorg.com myhostname', out) + self.assertIn('127.0.0.1 localhost', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/set_password.py b/tests/cloud_tests/testcases/modules/set_password.py new file mode 100644 index 00000000..1411a296 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/set_password.py @@ -0,0 +1,22 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestPassword(base.CloudTestCase): + """Test password module""" + + # TODO add test to make sure password is actually "password" + + def test_shadow(self): + """Test ubuntu user in shadow""" + out = self.get_data_file('shadow') + self.assertIn('ubuntu:', out) + + def test_sshd_config(self): + """Test sshd config allows passwords""" + out = self.get_data_file('sshd_config') + self.assertIn('PasswordAuthentication yes', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/set_password_expire.py b/tests/cloud_tests/testcases/modules/set_password_expire.py new file mode 100644 index 00000000..1ac9c23f --- /dev/null +++ b/tests/cloud_tests/testcases/modules/set_password_expire.py @@ -0,0 +1,23 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestPasswordExpire(base.CloudTestCase): + """Test password module""" + + def test_shadow(self): + """Test user frozen in shadow""" + out = self.get_data_file('shadow') + self.assertIn('harry:!:', out) + self.assertIn('dick:!:', out) + self.assertIn('tom:!:', out) + self.assertIn('harry:!:', out) + + def test_sshd_config(self): + """Test sshd config allows passwords""" + out = self.get_data_file('sshd_config') + self.assertIn('PasswordAuthentication no', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/set_password_list.py b/tests/cloud_tests/testcases/modules/set_password_list.py new file mode 100644 index 00000000..b764362f --- /dev/null +++ b/tests/cloud_tests/testcases/modules/set_password_list.py @@ -0,0 +1,25 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestPasswordList(base.CloudTestCase): + """Test password module""" + + # TODO: Verify dick and harry passwords are random + # TODO: Verify tom's password was changed + + def test_shadow(self): + """Test every tom, dick, and harry user in shadow""" + out = self.get_data_file('shadow') + self.assertIn('tom:', out) + self.assertIn('dick:', out) + self.assertIn('harry:', out) + + def test_sshd_config(self): + """Test sshd config allows passwords""" + out = self.get_data_file('sshd_config') + self.assertIn('PasswordAuthentication yes', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/snappy.py b/tests/cloud_tests/testcases/modules/snappy.py new file mode 100644 index 00000000..3e2f5924 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/snappy.py @@ -0,0 +1,18 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestSnappy(base.CloudTestCase): + """Test snappy module""" + + def test_snappy_version(self): + """Test snappy version output""" + out = self.get_data_file('snap_version') + self.assertIn('snap ', out) + self.assertIn('snapd ', out) + self.assertIn('series ', out) + self.assertIn('ubuntu ', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.py b/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.py new file mode 100644 index 00000000..a0f8896b --- /dev/null +++ b/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.py @@ -0,0 +1,24 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestSshKeyFingerprintsDisable(base.CloudTestCase): + """Test ssh key fingerprints module""" + + def test_cloud_init_log(self): + """Verify disabled""" + out = self.get_data_file('cloud-init.log') + self.assertIn('Skipping module named ssh-authkey-fingerprints, ' + 'logging of ssh fingerprints disabled', out) + + def test_syslog(self): + """Verify output of syslog""" + out = self.get_data_file('syslog') + self.assertNotRegexpMatches(out, r'256 SHA256:.*(ECDSA)') + self.assertNotRegexpMatches(out, r'256 SHA256:.*(ED25519)') + self.assertNotRegexpMatches(out, r'1024 SHA256:.*(DSA)') + self.assertNotRegexpMatches(out, r'2048 SHA256:.*(RSA)') + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.py b/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.py new file mode 100644 index 00000000..3c44b0cc --- /dev/null +++ b/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.py @@ -0,0 +1,18 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestSshKeyFingerprintsEnable(base.CloudTestCase): + """Test ssh key fingerprints module""" + + def test_syslog(self): + """Verify output of syslog""" + out = self.get_data_file('syslog') + self.assertRegexpMatches(out, r'256 SHA256:.*(ECDSA)') + self.assertRegexpMatches(out, r'256 SHA256:.*(ED25519)') + self.assertNotRegexpMatches(out, r'1024 SHA256:.*(DSA)') + self.assertNotRegexpMatches(out, r'2048 SHA256:.*(RSA)') + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/ssh_import_id.py b/tests/cloud_tests/testcases/modules/ssh_import_id.py new file mode 100644 index 00000000..214e710d --- /dev/null +++ b/tests/cloud_tests/testcases/modules/ssh_import_id.py @@ -0,0 +1,26 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestSshImportId(base.CloudTestCase): + """Test ssh import id module""" + + def test_authorized_keys(self): + """Test that ssh keys were imported""" + out = self.get_data_file('auth_keys_ubuntu') + + # Rather than checking the key fingerprints, you could just check + # the ending comment for where it got imported from in case these + # change in the future :\ + self.assertIn('8sXGTYYw3iQSkOvDUUlIsqdaO+w== powersj@github/' + '18564351 # ssh-import-id gh:powersj', out) + self.assertIn('Hj29SCmXp5Kt5/82cD/VN3NtHw== smoser@brickies-' + 'canonical # ssh-import-id lp:smoser', out) + self.assertIn('7cUDQSXbabilgnzTjHo9mjd/kZ7cLOHP smoser@bart-' + 'canonical # ssh-import-id lp:smoser', out) + self.assertIn('aX0VHGXvHAQlPl4n7+FzAE1UmWFYEGrsSoNvLv3 smose' + 'r@kaypeah # ssh-import-id lp:smoser', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/ssh_keys_generate.py b/tests/cloud_tests/testcases/modules/ssh_keys_generate.py new file mode 100644 index 00000000..161ace5f --- /dev/null +++ b/tests/cloud_tests/testcases/modules/ssh_keys_generate.py @@ -0,0 +1,57 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestSshKeysGenerate(base.CloudTestCase): + """Test ssh keys module""" + + # TODO: Check cloud-init-output for the correct keys being generated + + def test_ubuntu_authorized_keys(self): + """Test passed in key is not in list for ubuntu""" + out = self.get_data_file('auth_keys_ubuntu') + self.assertEqual('', out) + + def test_dsa_public(self): + """Test dsa public key not generated""" + out = self.get_data_file('dsa_public') + self.assertEqual('', out) + + def test_dsa_private(self): + """Test dsa private key not generated""" + out = self.get_data_file('dsa_private') + self.assertEqual('', out) + + def test_rsa_public(self): + """Test rsa public key not generated""" + out = self.get_data_file('rsa_public') + self.assertEqual('', out) + + def test_rsa_private(self): + """Test rsa public key not generated""" + out = self.get_data_file('rsa_private') + self.assertEqual('', out) + + def test_ecdsa_public(self): + """Test ecdsa public key generated""" + out = self.get_data_file('ecdsa_public') + self.assertIsNotNone(out) + + def test_ecdsa_private(self): + """Test ecdsa public key generated""" + out = self.get_data_file('ecdsa_private') + self.assertIsNotNone(out) + + def test_ed25519_public(self): + """Test ed25519 public key generated""" + out = self.get_data_file('ed25519_public') + self.assertIsNotNone(out) + + def test_ed25519_private(self): + """Test ed25519 public key generated""" + out = self.get_data_file('ed25519_private') + self.assertIsNotNone(out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/ssh_keys_provided.py b/tests/cloud_tests/testcases/modules/ssh_keys_provided.py new file mode 100644 index 00000000..8f18cb94 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/ssh_keys_provided.py @@ -0,0 +1,69 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestSshKeysProvided(base.CloudTestCase): + """Test ssh keys module""" + + def test_ubuntu_authorized_keys(self): + """Test passed in key is not in list for ubuntu""" + out = self.get_data_file('auth_keys_ubuntu') + self.assertEqual('', out) + + def test_root_authorized_keys(self): + """Test passed in key is in authorized list for root""" + out = self.get_data_file('auth_keys_root') + self.assertIn('lzrkPqONphoZx0LDV86w7RUz1ksDzAdcm0tvmNRFMN1a0frDs50' + '6oA3aWK0oDk4Nmvk8sXGTYYw3iQSkOvDUUlIsqdaO+w==', out) + + def test_dsa_public(self): + """Test dsa public key passed in""" + out = self.get_data_file('dsa_public') + self.assertIn('AAAAB3NzaC1kc3MAAACBAPkWy1zbchVIN7qTgM0/yyY8q4RZS8c' + 'NM4ZpeuE5UB/Nnr6OSU/nmbO8LuM', out) + + def test_dsa_private(self): + """Test dsa private key passed in""" + out = self.get_data_file('dsa_private') + self.assertIn('MIIBuwIBAAKBgQD5Fstc23IVSDe6k4DNP8smPKuEWUvHDTOGaXr' + 'hOVAfzZ6+jklP', out) + + def test_rsa_public(self): + """Test rsa public key passed in""" + out = self.get_data_file('rsa_public') + self.assertIn('AAAAB3NzaC1yc2EAAAADAQABAAABAQC0/Ho+o3eJISydO2JvIgT' + 'LnZOtrxPl+fSvJfKDjoOLY0HB2eOjy2s2/2N6d9X9SGZ4', out) + + def test_rsa_private(self): + """Test rsa public key passed in""" + out = self.get_data_file('rsa_private') + self.assertIn('4DOkqNiUGl80Zp1RgZNohHUXlJMtAbrIlAVEk+mTmg7vjfyp2un' + 'RQvLZpMRdywBm', out) + + def test_ecdsa_public(self): + """Test ecdsa public key passed in""" + out = self.get_data_file('ecdsa_public') + self.assertIn('AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAAB' + 'BBFsS5Tvky/IC/dXhE/afxxU', out) + + def test_ecdsa_private(self): + """Test ecdsa public key passed in""" + out = self.get_data_file('ecdsa_private') + self.assertIn('AwEHoUQDQgAEWxLlO+TL8gL91eET9p/HFQbqR1A691AkJgZk3jY' + '5mpZqxgX4vcgb', out) + + def test_ed25519_public(self): + """Test ed25519 public key passed in""" + out = self.get_data_file('ed25519_public') + self.assertIn('AAAAC3NzaC1lZDI1NTE5AAAAINudAZSu4vjZpVWzId5pXmZg1M6' + 'G15dqjQ2XkNVOEnb5', out) + + def test_ed25519_private(self): + """Test ed25519 public key passed in""" + out = self.get_data_file('ed25519_private') + self.assertIn('XAAAAAtzc2gtZWQyNTUxOQAAACDbnQGUruL42aVVsyHeaV5mYNT' + 'OhteXao0Nl5DVThJ2+Q', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/timezone.py b/tests/cloud_tests/testcases/modules/timezone.py new file mode 100644 index 00000000..272c266f --- /dev/null +++ b/tests/cloud_tests/testcases/modules/timezone.py @@ -0,0 +1,15 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestTimezone(base.CloudTestCase): + """Test timezone module""" + + def test_timezone(self): + """Test date prints correct timezone""" + out = self.get_data_file('timezone') + self.assertIn('HST', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/user_groups.py b/tests/cloud_tests/testcases/modules/user_groups.py new file mode 100644 index 00000000..e5732322 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/user_groups.py @@ -0,0 +1,43 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestUserGroups(base.CloudTestCase): + """Example cloud-config test""" + + def test_group_ubuntu(self): + """Test ubuntu group exists""" + out = self.get_data_file('group_ubuntu') + self.assertRegex(out, r'ubuntu:x:[0-9]{4}:') + + def test_group_cloud_users(self): + """Test cloud users group exists""" + out = self.get_data_file('group_cloud_users') + self.assertRegex(out, r'cloud-users:x:[0-9]{4}:barfoo') + + def test_user_ubuntu(self): + """Test ubuntu user exists""" + out = self.get_data_file('user_ubuntu') + self.assertRegex( + out, r'ubuntu:x:[0-9]{4}:[0-9]{4}:Ubuntu:/home/ubuntu:/bin/bash') + + def test_user_foobar(self): + """Test foobar user exists""" + out = self.get_data_file('user_foobar') + self.assertRegex( + out, r'foobar:x:[0-9]{4}:[0-9]{4}:Foo B. Bar:/home/foobar:') + + def test_user_barfoo(self): + """Test barfoo user exists""" + out = self.get_data_file('user_barfoo') + self.assertRegex( + out, r'barfoo:x:[0-9]{4}:[0-9]{4}:Bar B. Foo:/home/barfoo:') + + def test_user_cloudy(self): + """Test cloudy user exists""" + out = self.get_data_file('user_cloudy') + self.assertRegex(out, r'cloudy:x:[0-9]{3,4}:') + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/testcases/modules/write_files.py b/tests/cloud_tests/testcases/modules/write_files.py new file mode 100644 index 00000000..97dfeec3 --- /dev/null +++ b/tests/cloud_tests/testcases/modules/write_files.py @@ -0,0 +1,30 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +"""cloud-init Integration Test Verify Script""" +from tests.cloud_tests.testcases import base + + +class TestWriteFiles(base.CloudTestCase): + """Example cloud-config test""" + + def test_b64(self): + """Test b64 encoded file reads as ascii""" + out = self.get_data_file('file_b64') + self.assertIn('ASCII text', out) + + def test_binary(self): + """Test binary file reads as executable""" + out = self.get_data_file('file_binary') + self.assertIn('ELF 64-bit LSB executable, x86-64, version 1', out) + + def test_gzip(self): + """Test gzip file shows up as a shell script""" + out = self.get_data_file('file_gzip') + self.assertIn('POSIX shell script, ASCII text executable', out) + + def test_text(self): + """Test text shows up as ASCII text""" + out = self.get_data_file('file_text') + self.assertIn('ASCII text', out) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/util.py b/tests/cloud_tests/util.py new file mode 100644 index 00000000..64a86672 --- /dev/null +++ b/tests/cloud_tests/util.py @@ -0,0 +1,163 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +import glob +import os +import random +import string +import tempfile +import yaml + +from cloudinit.distros import OSFAMILIES +from cloudinit import util as c_util +from tests.cloud_tests import LOG + + +def list_test_data(data_dir): + """ + find all tests with test data available in data_dir + data_dir should contain <platforms>/<os_name>/<testnames>/<data> + return_value: {<platform>: {<os_name>: [<testname>]}} + """ + if not os.path.isdir(data_dir): + raise ValueError("bad data dir") + + res = {} + for platform in os.listdir(data_dir): + res[platform] = {} + for os_name in os.listdir(os.path.join(data_dir, platform)): + res[platform][os_name] = [ + os.path.sep.join(f.split(os.path.sep)[-2:]) for f in + glob.glob(os.sep.join((data_dir, platform, os_name, '*/*')))] + + LOG.debug('found test data: %s\n', res) + return res + + +def gen_instance_name(prefix='cloud-test', image_desc=None, use_desc=None, + max_len=63, delim='-', max_tries=16, used_list=None, + valid=string.ascii_lowercase + string.digits): + """ + generate an unique name for a test instance + prefix: name prefix, defaults to cloud-test, default should be left + image_desc: short string with image desc, will be truncated to 16 chars + use_desc: short string with usage desc, will be truncated to 30 chars + max_len: maximum name length, defaults to 64 chars + delim: delimiter to use between tokens + max_tries: maximum tries to find a unique name before giving up + used_list: already used names, or none to not check + valid: string of valid characters for name + return_value: valid, unused name, may raise StopIteration + """ + unknown = 'unknown' + + def join(*args): + """ + join args with delim + """ + return delim.join(args) + + def fill(*args): + """ + join name elems and fill rest with random data + """ + name = join(*args) + num = max_len - len(name) - len(delim) + return join(name, ''.join(random.choice(valid) for _ in range(num))) + + def clean(elem, max_len): + """ + filter bad characters out of elem and trim to length + """ + elem = elem[:max_len] if elem else unknown + return ''.join(c if c in valid else delim for c in elem) + + return next(name for name in + (fill(prefix, clean(image_desc, 16), clean(use_desc, 30)) + for _ in range(max_tries)) + if not used_list or name not in used_list) + + +def sorted_unique(iterable, key=None, reverse=False): + """ + return_value: a sorted list of unique items in iterable + """ + return sorted(set(iterable), key=key, reverse=reverse) + + +def get_os_family(os_name): + """ + get os family type for os_name + """ + return next((k for k, v in OSFAMILIES.items() if os_name in v), None) + + +def current_verbosity(): + """ + get verbosity currently in effect from log level + return_value: verbosity, 0-2, 2 = verbose, 0 = quiet + """ + return max(min(3 - int(LOG.level / 10), 2), 0) + + +def is_writable_dir(path): + """ + make sure dir is writable + """ + try: + c_util.ensure_dir(path) + os.remove(tempfile.mkstemp(dir=os.path.abspath(path))[1]) + except (IOError, OSError): + return False + return True + + +def is_clean_writable_dir(path): + """ + make sure dir is empty and writable, creating it if it does not exist + return_value: True/False if successful + """ + path = os.path.abspath(path) + if not (is_writable_dir(path) and len(os.listdir(path)) == 0): + return False + return True + + +def configure_yaml(): + yaml.add_representer(str, (lambda dumper, data: dumper.represent_scalar( + 'tag:yaml.org,2002:str', data, style='|' if '\n' in data else ''))) + + +def yaml_format(data): + """ + format data as yaml + """ + configure_yaml() + return yaml.dump(data, indent=2, default_flow_style=False) + + +def yaml_dump(data, path): + """ + dump data to path in yaml format + """ + write_file(os.path.abspath(path), yaml_format(data), omode='w') + + +def merge_results(data, path): + """ + handle merging results from collect phase and verify phase + """ + current = {} + if os.path.exists(path): + with open(path, 'r') as fp: + current = c_util.load_yaml(fp.read()) + current.update(data) + yaml_dump(current, path) + + +def write_file(*args, **kwargs): + """ + write a file using cloudinit.util.write_file + """ + c_util.write_file(*args, **kwargs) + +# vi: ts=4 expandtab diff --git a/tests/cloud_tests/verify.py b/tests/cloud_tests/verify.py new file mode 100644 index 00000000..ef7d4e21 --- /dev/null +++ b/tests/cloud_tests/verify.py @@ -0,0 +1,93 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from tests.cloud_tests import (config, LOG, util, testcases) + +import os +import unittest + + +def verify_data(base_dir, tests): + """ + verify test data is correct, + base_dir: base directory for data + test_config: dict of all test config, from util.load_test_config() + tests: list of test names + return_value: {<test_name>: {passed: True/False, failures: []}} + """ + runner = unittest.TextTestRunner(verbosity=util.current_verbosity()) + res = {} + for test_name in tests: + LOG.debug('verifying test data for %s', test_name) + + # get cloudconfig for test + test_conf = config.load_test_config(test_name) + test_module = config.name_to_module(test_name) + cloud_conf = test_conf['cloud_config'] + + # load script outputs + data = {} + test_dir = os.path.join(base_dir, test_name) + for script_name in os.listdir(test_dir): + with open(os.path.join(test_dir, script_name), 'r') as fp: + data[script_name] = fp.read() + + # get test suite and launch tests + suite = testcases.get_suite(test_module, data, cloud_conf) + suite_results = runner.run(suite) + res[test_name] = { + 'passed': suite_results.wasSuccessful(), + 'failures': [{'module': type(test_class).__base__.__module__, + 'class': type(test_class).__base__.__name__, + 'function': str(test_class).split()[0], + 'error': trace.splitlines()[-1], + 'traceback': trace, } + for test_class, trace in suite_results.failures] + } + + for failure in res[test_name]['failures']: + LOG.warn('test case: %s failed %s.%s with: %s', + test_name, failure['class'], failure['function'], + failure['error']) + + return res + + +def verify(args): + """ + verify test data + return_value: 0 for success, or number of failed tests + """ + failed = 0 + res = {} + + # find test data + tests = util.list_test_data(args.data_dir) + + for platform in tests.keys(): + res[platform] = {} + for os_name in tests[platform].keys(): + test_name = "platform='{}', os='{}'".format(platform, os_name) + LOG.info('test: %s verifying test data', test_name) + + # run test + res[platform][os_name] = verify_data( + os.sep.join((args.data_dir, platform, os_name)), + tests[platform][os_name]) + + # handle results + fail_list = [k for k, v in res[platform][os_name].items() + if not v.get('passed')] + if len(fail_list) == 0: + LOG.info('test: %s passed all tests', test_name) + else: + LOG.warn('test: %s failed %s tests', test_name, len(fail_list)) + failed += len(fail_list) + + # dump results + LOG.debug('verify results: %s', res) + if args.result: + util.merge_results({'verify': res}, args.result) + + return failed + +# vi: ts=4 expandtab diff --git a/tests/data/merge_sources/expected8.yaml b/tests/data/merge_sources/expected8.yaml index 69ca562d..360e38f0 100644 --- a/tests/data/merge_sources/expected8.yaml +++ b/tests/data/merge_sources/expected8.yaml @@ -3,5 +3,5 @@ mounts: - [ ephemeral22, /mnt, auto, "defaults,noexec" ] - [ sdc, /opt/data ] - - [ xvdh, /opt/data, "auto", "defaults,nobootwait", "0", "0" ] + - [ xvdh, /opt/data, "auto", "defaults,nofail", "0", "0" ] - [ dd, /dev/zero ] diff --git a/tests/data/merge_sources/source8-1.yaml b/tests/data/merge_sources/source8-1.yaml index 5ea51c2c..1ac1b0dd 100644 --- a/tests/data/merge_sources/source8-1.yaml +++ b/tests/data/merge_sources/source8-1.yaml @@ -3,5 +3,5 @@ mounts: - [ ephemeral0, /mnt, auto, "defaults,noexec" ] - [ sdc, /opt/data ] - - [ xvdh, /opt/data, "auto", "defaults,nobootwait", "0", "0" ] + - [ xvdh, /opt/data, "auto", "defaults,nofail", "0", "0" ] - [ dd, /dev/zero ] diff --git a/tests/unittests/__init__.py b/tests/unittests/__init__.py index 1b34b5af..d89ed443 100644 --- a/tests/unittests/__init__.py +++ b/tests/unittests/__init__.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + try: # For test cases, avoid the following UserWarning to stderr: # You don't have the C version of NameMapper installed ... diff --git a/tests/unittests/helpers.py b/tests/unittests/helpers.py index a2355a79..cf3b46d2 100644 --- a/tests/unittests/helpers.py +++ b/tests/unittests/helpers.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from __future__ import print_function import functools @@ -300,6 +302,39 @@ def dir2dict(startdir, prefix=None): return flist +def wrap_and_call(prefix, mocks, func, *args, **kwargs): + """ + call func(args, **kwargs) with mocks applied, then unapplies mocks + nicer to read than repeating dectorators on each function + + prefix: prefix for mock names (e.g. 'cloudinit.stages.util') or None + mocks: dictionary of names (under 'prefix') to mock and either + a return value or a dictionary to pass to the mock.patch call + func: function to call with mocks applied + *args,**kwargs: arguments for 'func' + + return_value: return from 'func' + """ + delim = '.' + if prefix is None: + prefix = '' + prefix = prefix.rstrip(delim) + unwraps = [] + for fname, kw in mocks.items(): + if prefix: + fname = delim.join((prefix, fname)) + if not isinstance(kw, dict): + kw = {'return_value': kw} + p = mock.patch(fname, **kw) + p.start() + unwraps.append(p) + try: + return func(*args, **kwargs) + finally: + for p in unwraps: + p.stop() + + try: skipIf = unittest.skipIf except AttributeError: @@ -313,3 +348,5 @@ except AttributeError: print(reason, file=sys.stderr) return wrapper return decorator + +# vi: ts=4 expandtab diff --git a/tests/unittests/test__init__.py b/tests/unittests/test__init__.py index 0154784a..7b6f8c4e 100644 --- a/tests/unittests/test__init__.py +++ b/tests/unittests/test__init__.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import os import shutil import tempfile diff --git a/tests/unittests/test_atomic_helper.py b/tests/unittests/test_atomic_helper.py index feb81551..e170c7c3 100644 --- a/tests/unittests/test_atomic_helper.py +++ b/tests/unittests/test_atomic_helper.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import json import os import stat @@ -52,3 +54,5 @@ class TestAtomicHelper(helpers.TempDirTestCase): def check_perms(self, path, perms): file_stat = os.stat(path) self.assertEqual(perms, stat.S_IMODE(file_stat.st_mode)) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_builtin_handlers.py b/tests/unittests/test_builtin_handlers.py index dea908d7..dd9d0357 100644 --- a/tests/unittests/test_builtin_handlers.py +++ b/tests/unittests/test_builtin_handlers.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + """Tests of the built-in user data handlers.""" import os @@ -71,3 +73,5 @@ class TestBuiltins(test_helpers.FilesystemMockingTestCase): mockobj.assert_called_once_with( ['initctl', 'reload-configuration'], capture=False) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_cli.py b/tests/unittests/test_cli.py index 5fa252f7..06f366b2 100644 --- a/tests/unittests/test_cli.py +++ b/tests/unittests/test_cli.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import six from . import helpers as test_helpers @@ -32,3 +34,6 @@ class TestCLI(test_helpers.FilesystemMockingTestCase): self.assertIn('cloud-init: error: too few arguments', self.stderr.getvalue()) self.assertEqual(2, exit_code) + + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_cs_util.py b/tests/unittests/test_cs_util.py index 56c9ce9e..b8f5031c 100644 --- a/tests/unittests/test_cs_util.py +++ b/tests/unittests/test_cs_util.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from __future__ import print_function from . import helpers as test_helpers @@ -61,3 +63,5 @@ class CepkoResultTests(test_helpers.TestCase): self.assertEqual('much server', result[0]) self.assertTrue('very performance' in result) self.assertEqual(2, len(result)) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_data.py b/tests/unittests/test_data.py index 55d9b93f..4092d9ca 100644 --- a/tests/unittests/test_data.py +++ b/tests/unittests/test_data.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + """Tests for handling of userdata within cloud init.""" import gzip @@ -559,3 +561,56 @@ class TestConvertString(helpers.TestCase): text = "hi mom" msg = ud.convert_string(text) self.assertEqual(text, msg.get_payload(decode=False)) + + +class TestFetchBaseConfig(helpers.TestCase): + + def test_only_builtin_gets_builtin2(self): + ret = helpers.wrap_and_call( + 'cloudinit.stages.util', + {'read_conf_with_confd': None, + 'read_conf_from_cmdline': None}, + stages.fetch_base_config) + self.assertEqual(util.get_builtin_cfg(), ret) + + def test_conf_d_overrides_defaults(self): + builtin = util.get_builtin_cfg() + test_key = sorted(builtin)[0] + test_value = 'test' + ret = helpers.wrap_and_call( + 'cloudinit.stages.util', + {'read_conf_with_confd': {'return_value': {test_key: test_value}}, + 'read_conf_from_cmdline': None}, + stages.fetch_base_config) + self.assertEqual(ret.get(test_key), test_value) + builtin[test_key] = test_value + self.assertEqual(ret, builtin) + + def test_cmdline_overrides_defaults(self): + builtin = util.get_builtin_cfg() + test_key = sorted(builtin)[0] + test_value = 'test' + cmdline = {test_key: test_value} + ret = helpers.wrap_and_call( + 'cloudinit.stages.util', + {'read_conf_from_cmdline': {'return_value': cmdline}, + 'read_conf_with_confd': None}, + stages.fetch_base_config) + self.assertEqual(ret.get(test_key), test_value) + builtin[test_key] = test_value + self.assertEqual(ret, builtin) + + def test_cmdline_overrides_conf_d_and_defaults(self): + builtin = {'key1': 'value0', 'key3': 'other2'} + conf_d = {'key1': 'value1', 'key2': 'other1'} + cmdline = {'key3': 'other3', 'key2': 'other2'} + ret = helpers.wrap_and_call( + 'cloudinit.stages.util', + {'read_conf_with_confd': {'return_value': conf_d}, + 'get_builtin_cfg': {'return_value': builtin}, + 'read_conf_from_cmdline': {'return_value': cmdline}}, + stages.fetch_base_config) + self.assertEqual(ret, {'key1': 'value1', 'key2': 'other2', + 'key3': 'other3'}) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_aliyun.py b/tests/unittests/test_datasource/test_aliyun.py index 6f1de072..c16d1a6e 100644 --- a/tests/unittests/test_datasource/test_aliyun.py +++ b/tests/unittests/test_datasource/test_aliyun.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import functools import httpretty import os @@ -146,3 +148,5 @@ class TestAliYunDatasource(test_helpers.HttprettyTestCase): 'ssh-key-1']}} self.assertEqual(ay.parse_public_keys(public_keys), public_keys['key-pair-0']['openssh-key']) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_altcloud.py b/tests/unittests/test_datasource/test_altcloud.py index 12966563..b0ad86ab 100644 --- a/tests/unittests/test_datasource/test_altcloud.py +++ b/tests/unittests/test_datasource/test_altcloud.py @@ -1,22 +1,11 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# Copyright (C) 2012 Yahoo! Inc. -# -# Author: Joe VLcek <JVLcek@RedHat.com> +# Copyright (C) 2009-2010 Canonical Ltd. +# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2012 Yahoo! Inc. # -# 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. +# Author: Joe VLcek <JVLcek@RedHat.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. + ''' This test file exercises the code in sources DataSourceAltCloud.py ''' @@ -448,5 +437,4 @@ def force_arch(arch=None): elif arch is None: setattr(os, 'uname', OS_UNAME_ORIG) - # vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py index 07127008..8d22bb59 100644 --- a/tests/unittests/test_datasource/test_azure.py +++ b/tests/unittests/test_datasource/test_azure.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit import helpers from cloudinit.util import b64e, decode_binary, load_file from cloudinit.sources import DataSourceAzure @@ -93,7 +95,7 @@ class TestAzureDataSource(TestCase): for module, name, new in patches: self.patches.enter_context(mock.patch.object(module, name, new)) - def _get_ds(self, data): + def _get_ds(self, data, agent_command=None): def dsdevs(): return data.get('dsdevs', []) @@ -137,6 +139,8 @@ class TestAzureDataSource(TestCase): dsrc = mod.DataSourceAzureNet( data.get('sys_cfg', {}), distro=None, paths=self.paths) + if agent_command is not None: + dsrc.ds_cfg['agent_command'] = agent_command return dsrc @@ -299,7 +303,7 @@ class TestAzureDataSource(TestCase): data = {'ovfcontent': construct_valid_ovf_env(data=odata, pubkeys=pubkeys)} - dsrc = self._get_ds(data) + dsrc = self._get_ds(data, agent_command=['not', '__builtin__']) ret = dsrc.get_data() self.assertTrue(ret) for mypk in mypklist: @@ -314,7 +318,7 @@ class TestAzureDataSource(TestCase): data = {'ovfcontent': construct_valid_ovf_env(data=odata, pubkeys=pubkeys)} - dsrc = self._get_ds(data) + dsrc = self._get_ds(data, agent_command=['not', '__builtin__']) ret = dsrc.get_data() self.assertTrue(ret) @@ -330,7 +334,7 @@ class TestAzureDataSource(TestCase): data = {'ovfcontent': construct_valid_ovf_env(data=odata, pubkeys=pubkeys)} - dsrc = self._get_ds(data) + dsrc = self._get_ds(data, agent_command=['not', '__builtin__']) ret = dsrc.get_data() self.assertTrue(ret) @@ -487,12 +491,15 @@ class TestAzureBounce(TestCase): def tearDown(self): self.patches.close() - def _get_ds(self, ovfcontent=None): + def _get_ds(self, ovfcontent=None, agent_command=None): if ovfcontent is not None: populate_dir(os.path.join(self.paths.seed_dir, "azure"), {'ovf-env.xml': ovfcontent}) - return DataSourceAzure.DataSourceAzureNet( + dsrc = DataSourceAzure.DataSourceAzureNet( {}, distro=None, paths=self.paths) + if agent_command is not None: + dsrc.ds_cfg['agent_command'] = agent_command + return dsrc def get_ovf_env_with_dscfg(self, hostname, cfg): odata = { @@ -537,14 +544,17 @@ class TestAzureBounce(TestCase): host_name = 'unchanged-host-name' self.get_hostname.return_value = host_name cfg = {'hostname_bounce': {'policy': 'force'}} - self._get_ds(self.get_ovf_env_with_dscfg(host_name, cfg)).get_data() + self._get_ds(self.get_ovf_env_with_dscfg(host_name, cfg), + agent_command=['not', '__builtin__']).get_data() self.assertEqual(1, perform_hostname_bounce.call_count) def test_different_hostnames_sets_hostname(self): expected_hostname = 'azure-expected-host-name' self.get_hostname.return_value = 'default-host-name' self._get_ds( - self.get_ovf_env_with_dscfg(expected_hostname, {})).get_data() + self.get_ovf_env_with_dscfg(expected_hostname, {}), + agent_command=['not', '__builtin__'], + ).get_data() self.assertEqual(expected_hostname, self.set_hostname.call_args_list[0][0][0]) @@ -554,14 +564,18 @@ class TestAzureBounce(TestCase): expected_hostname = 'azure-expected-host-name' self.get_hostname.return_value = 'default-host-name' self._get_ds( - self.get_ovf_env_with_dscfg(expected_hostname, {})).get_data() + self.get_ovf_env_with_dscfg(expected_hostname, {}), + agent_command=['not', '__builtin__'], + ).get_data() self.assertEqual(1, perform_hostname_bounce.call_count) def test_different_hostnames_sets_hostname_back(self): initial_host_name = 'default-host-name' self.get_hostname.return_value = initial_host_name self._get_ds( - self.get_ovf_env_with_dscfg('some-host-name', {})).get_data() + self.get_ovf_env_with_dscfg('some-host-name', {}), + agent_command=['not', '__builtin__'], + ).get_data() self.assertEqual(initial_host_name, self.set_hostname.call_args_list[-1][0][0]) @@ -572,7 +586,9 @@ class TestAzureBounce(TestCase): initial_host_name = 'default-host-name' self.get_hostname.return_value = initial_host_name self._get_ds( - self.get_ovf_env_with_dscfg('some-host-name', {})).get_data() + self.get_ovf_env_with_dscfg('some-host-name', {}), + agent_command=['not', '__builtin__'], + ).get_data() self.assertEqual(initial_host_name, self.set_hostname.call_args_list[-1][0][0]) @@ -583,7 +599,7 @@ class TestAzureBounce(TestCase): self.get_hostname.return_value = old_hostname cfg = {'hostname_bounce': {'interface': interface, 'policy': 'force'}} data = self.get_ovf_env_with_dscfg(hostname, cfg) - self._get_ds(data).get_data() + self._get_ds(data, agent_command=['not', '__builtin__']).get_data() self.assertEqual(1, self.subp.call_count) bounce_env = self.subp.call_args[1]['env'] self.assertEqual(interface, bounce_env['interface']) @@ -595,7 +611,7 @@ class TestAzureBounce(TestCase): DataSourceAzure.BUILTIN_DS_CONFIG['hostname_bounce']['command'] = cmd cfg = {'hostname_bounce': {'policy': 'force'}} data = self.get_ovf_env_with_dscfg('some-hostname', cfg) - self._get_ds(data).get_data() + self._get_ds(data, agent_command=['not', '__builtin__']).get_data() self.assertEqual(1, self.subp.call_count) bounce_args = self.subp.call_args[1]['args'] self.assertEqual(cmd, bounce_args) @@ -630,3 +646,5 @@ class TestReadAzureOvf(TestCase): (_md, _ud, cfg) = DataSourceAzure.read_azure_ovf(content) for mypk in mypklist: self.assertIn(mypk, cfg['_pubkeys']) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_azure_helper.py b/tests/unittests/test_datasource/test_azure_helper.py index 64523e16..aafdebd7 100644 --- a/tests/unittests/test_datasource/test_azure_helper.py +++ b/tests/unittests/test_datasource/test_azure_helper.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import os from cloudinit.sources.helpers import azure as azure_helper @@ -419,3 +421,5 @@ class TestGetMetadataFromFabric(TestCase): self.assertRaises(SentinelException, azure_helper.get_metadata_from_fabric) self.assertEqual(1, shim.return_value.clean_up.call_count) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_cloudsigma.py b/tests/unittests/test_datasource/test_cloudsigma.py index 2a42ce0c..5997102c 100644 --- a/tests/unittests/test_datasource/test_cloudsigma.py +++ b/tests/unittests/test_datasource/test_cloudsigma.py @@ -1,8 +1,9 @@ -# coding: utf-8 +# This file is part of cloud-init. See LICENSE file for license information. import copy from cloudinit.cs_utils import Cepko +from cloudinit import sources from cloudinit.sources import DataSourceCloudSigma from .. import helpers as test_helpers @@ -49,7 +50,8 @@ class DataSourceCloudSigmaTest(test_helpers.TestCase): self.assertEqual("test_server", self.datasource.get_hostname()) self.datasource.metadata['name'] = '' self.assertEqual("65b2fb23", self.datasource.get_hostname()) - self.datasource.metadata['name'] = u'тест' + utf8_hostname = b'\xd1\x82\xd0\xb5\xd1\x81\xd1\x82'.decode('utf-8') + self.datasource.metadata['name'] = utf8_hostname self.assertEqual("65b2fb23", self.datasource.get_hostname()) def test_get_public_ssh_keys(self): @@ -97,3 +99,19 @@ class DataSourceCloudSigmaTest(test_helpers.TestCase): self.datasource.get_data() self.assertIsNone(self.datasource.vendordata_raw) + + +class DsLoads(test_helpers.TestCase): + def test_get_datasource_list_returns_in_local(self): + deps = (sources.DEP_FILESYSTEM,) + ds_list = DataSourceCloudSigma.get_datasource_list(deps) + self.assertEqual(ds_list, + [DataSourceCloudSigma.DataSourceCloudSigma]) + + def test_list_sources_finds_ds(self): + found = sources.list_sources( + ['CloudSigma'], (sources.DEP_FILESYSTEM,), ['cloudinit.sources']) + self.assertEqual([DataSourceCloudSigma.DataSourceCloudSigma], + found) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_cloudstack.py b/tests/unittests/test_datasource/test_cloudstack.py index b1aab17b..e93d28de 100644 --- a/tests/unittests/test_datasource/test_cloudstack.py +++ b/tests/unittests/test_datasource/test_cloudstack.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit import helpers from cloudinit.sources.DataSourceCloudStack import DataSourceCloudStack @@ -76,3 +78,5 @@ class TestCloudStackPasswordFetching(TestCase): def test_password_not_saved_if_bad_request(self): self._check_password_not_saved_for('bad_request') + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_common.py b/tests/unittests/test_datasource/test_common.py new file mode 100644 index 00000000..c08717f3 --- /dev/null +++ b/tests/unittests/test_datasource/test_common.py @@ -0,0 +1,75 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from cloudinit import settings +from cloudinit import sources +from cloudinit import type_utils +from cloudinit.sources import ( + DataSourceAliYun as AliYun, + DataSourceAltCloud as AltCloud, + DataSourceAzure as Azure, + DataSourceBigstep as Bigstep, + DataSourceCloudSigma as CloudSigma, + DataSourceCloudStack as CloudStack, + DataSourceConfigDrive as ConfigDrive, + DataSourceDigitalOcean as DigitalOcean, + DataSourceEc2 as Ec2, + DataSourceGCE as GCE, + DataSourceMAAS as MAAS, + DataSourceNoCloud as NoCloud, + DataSourceOpenNebula as OpenNebula, + DataSourceOpenStack as OpenStack, + DataSourceOVF as OVF, + DataSourceSmartOS as SmartOS, +) +from cloudinit.sources import DataSourceNone as DSNone + +from .. import helpers as test_helpers + +DEFAULT_LOCAL = [ + CloudSigma.DataSourceCloudSigma, + ConfigDrive.DataSourceConfigDrive, + DigitalOcean.DataSourceDigitalOcean, + NoCloud.DataSourceNoCloud, + OpenNebula.DataSourceOpenNebula, + OVF.DataSourceOVF, + SmartOS.DataSourceSmartOS, +] + +DEFAULT_NETWORK = [ + AltCloud.DataSourceAltCloud, + Azure.DataSourceAzureNet, + Bigstep.DataSourceBigstep, + CloudStack.DataSourceCloudStack, + DSNone.DataSourceNone, + Ec2.DataSourceEc2, + GCE.DataSourceGCE, + MAAS.DataSourceMAAS, + NoCloud.DataSourceNoCloudNet, + OpenStack.DataSourceOpenStack, + OVF.DataSourceOVFNet, +] + + +class ExpectedDataSources(test_helpers.TestCase): + builtin_list = settings.CFG_BUILTIN['datasource_list'] + deps_local = [sources.DEP_FILESYSTEM] + deps_network = [sources.DEP_FILESYSTEM, sources.DEP_NETWORK] + pkg_list = [type_utils.obj_name(sources)] + + def test_expected_default_local_sources_found(self): + found = sources.list_sources( + self.builtin_list, self.deps_local, self.pkg_list) + self.assertEqual(set(DEFAULT_LOCAL), set(found)) + + def test_expected_default_network_sources_found(self): + found = sources.list_sources( + self.builtin_list, self.deps_network, self.pkg_list) + self.assertEqual(set(DEFAULT_NETWORK), set(found)) + + def test_expected_nondefault_network_sources_found(self): + found = sources.list_sources( + ['AliYun'], self.deps_network, self.pkg_list) + self.assertEqual(set([AliYun.DataSourceAliYun]), set(found)) + + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_configdrive.py b/tests/unittests/test_datasource/test_configdrive.py index 6e00abf4..55153357 100644 --- a/tests/unittests/test_datasource/test_configdrive.py +++ b/tests/unittests/test_datasource/test_configdrive.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from copy import copy, deepcopy import json import os diff --git a/tests/unittests/test_datasource/test_digitalocean.py b/tests/unittests/test_datasource/test_digitalocean.py index 7bde0820..9be6bc19 100644 --- a/tests/unittests/test_datasource/test_digitalocean.py +++ b/tests/unittests/test_datasource/test_digitalocean.py @@ -1,19 +1,8 @@ +# Copyright (C) 2014 Neal Shrader # -# Copyright (C) 2014 Neal Shrader +# Author: Neal Shrader <neal@digitalocean.com> # -# Author: Neal Shrader <neal@digitalocean.com> -# -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import json @@ -330,3 +319,5 @@ class TestNetworkConvert(TestCase): self.assertEqual( sorted(['45.55.249.133', '10.17.0.5']), sorted([i['address'] for i in eth0['subnets']])) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_gce.py b/tests/unittests/test_datasource/test_gce.py index 6e62a4d2..4f667678 100644 --- a/tests/unittests/test_datasource/test_gce.py +++ b/tests/unittests/test_datasource/test_gce.py @@ -1,19 +1,8 @@ +# Copyright (C) 2014 Vaidas Jablonskis # -# Copyright (C) 2014 Vaidas Jablonskis +# Author: Vaidas Jablonskis <jablonskis@gmail.com> # -# Author: Vaidas Jablonskis <jablonskis@gmail.com> -# -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import re @@ -164,3 +153,5 @@ class TestDataSourceGCE(test_helpers.HttprettyTestCase): _set_mock_metadata() self.ds.get_data() self.assertEqual('bar', self.ds.availability_zone) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_maas.py b/tests/unittests/test_datasource/test_maas.py index 0126c883..693882d2 100644 --- a/tests/unittests/test_datasource/test_maas.py +++ b/tests/unittests/test_datasource/test_maas.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from copy import copy import os import shutil diff --git a/tests/unittests/test_datasource/test_nocloud.py b/tests/unittests/test_datasource/test_nocloud.py index f6a46ce9..ff294395 100644 --- a/tests/unittests/test_datasource/test_nocloud.py +++ b/tests/unittests/test_datasource/test_nocloud.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit import helpers from cloudinit.sources import DataSourceNoCloud from cloudinit import util diff --git a/tests/unittests/test_datasource/test_opennebula.py b/tests/unittests/test_datasource/test_opennebula.py index ce5b5550..a266e952 100644 --- a/tests/unittests/test_datasource/test_opennebula.py +++ b/tests/unittests/test_datasource/test_opennebula.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit import helpers from cloudinit.sources import DataSourceOpenNebula as ds from cloudinit import util diff --git a/tests/unittests/test_datasource/test_openstack.py b/tests/unittests/test_datasource/test_openstack.py index 125c6d6e..e5b6fcc6 100644 --- a/tests/unittests/test_datasource/test_openstack.py +++ b/tests/unittests/test_datasource/test_openstack.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2014 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2014 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import copy import json @@ -344,3 +332,5 @@ class TestVendorDataLoading(test_helpers.TestCase): def test_vd_load_dict_ci_list(self): data = {'foo': 'bar', 'cloud-init': ['VD_1', 'VD_2']} self.assertEqual(self.cvj(data), data['cloud-init']) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_ovf.py b/tests/unittests/test_datasource/test_ovf.py index 5f8e7e44..3e09510c 100644 --- a/tests/unittests/test_datasource/test_ovf.py +++ b/tests/unittests/test_datasource/test_ovf.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2016 Canonical Ltd. -# -# Author: Scott Moser <scott.moser@canonical.com> +# Copyright (C) 2016 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. +# Author: Scott Moser <scott.moser@canonical.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import base64 @@ -81,3 +69,5 @@ class TestReadOvfEnv(test_helpers.TestCase): self.assertEqual({"instance-id": "inst-001"}, md) self.assertEqual({'password': "passw0rd"}, cfg) self.assertEqual(None, ud) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_datasource/test_smartos.py b/tests/unittests/test_datasource/test_smartos.py index 0532f986..e3c99bbb 100644 --- a/tests/unittests/test_datasource/test_smartos.py +++ b/tests/unittests/test_datasource/test_smartos.py @@ -1,26 +1,15 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2013 Canonical Ltd. -# -# Author: Ben Howard <ben.howard@canonical.com> -# -# 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 <http://www.gnu.org/licenses/>. +# Copyright (C) 2013 Canonical Ltd. # +# Author: Ben Howard <ben.howard@canonical.com> # -# This is a testcase for the SmartOS datasource. It replicates a serial -# console and acts like the SmartOS console does in order to validate -# return responses. -# +# This file is part of cloud-init. See LICENSE file for license information. + +'''This is a testcase for the SmartOS datasource. + +It replicates a serial console and acts like the SmartOS console does in +order to validate return responses. + +''' from __future__ import print_function @@ -881,3 +870,5 @@ class TestNetworkConversion(TestCase): 'type': 'static'}]}]} found = convert_net(SDC_NICS_SINGLE_GATEWAY) self.assertEqual(expected, found) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_distros/test_create_users.py b/tests/unittests/test_distros/test_create_users.py new file mode 100644 index 00000000..9ded4f6c --- /dev/null +++ b/tests/unittests/test_distros/test_create_users.py @@ -0,0 +1,151 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from cloudinit import distros +from ..helpers import (TestCase, mock) + + +class MyBaseDistro(distros.Distro): + # MyBaseDistro is here to test base Distro class implementations + + def __init__(self, name="basedistro", cfg={}, paths={}): + super(MyBaseDistro, self).__init__(name, cfg, paths) + + def install_packages(self, pkglist): + raise NotImplementedError() + + def _write_network(self, settings): + raise NotImplementedError() + + def package_command(self, cmd, args=None, pkgs=None): + raise NotImplementedError() + + def update_package_sources(self): + raise NotImplementedError() + + def apply_locale(self, locale, out_fn=None): + raise NotImplementedError() + + def set_timezone(self, tz): + raise NotImplementedError() + + def _read_hostname(self, filename, default=None): + raise NotImplementedError() + + def _write_hostname(self, hostname, filename): + raise NotImplementedError() + + def _read_system_hostname(self): + raise NotImplementedError() + + +class TestCreateUser(TestCase): + def setUp(self): + super(TestCase, self).setUp() + self.dist = MyBaseDistro() + + def _useradd2call(self, args): + # return a mock call for the useradd command in args + # with expected 'logstring'. + args = ['useradd'] + args + logcmd = [a for a in args] + for i in range(len(args)): + if args[i] in ('--password',): + logcmd[i + 1] = 'REDACTED' + return mock.call(args, logstring=logcmd) + + @mock.patch("cloudinit.distros.util.subp") + def test_basic(self, m_subp): + user = 'foouser' + self.dist.create_user(user) + self.assertEqual( + m_subp.call_args_list, + [self._useradd2call([user, '-m']), + mock.call(['passwd', '-l', user])]) + + @mock.patch("cloudinit.distros.util.subp") + def test_no_home(self, m_subp): + user = 'foouser' + self.dist.create_user(user, no_create_home=True) + self.assertEqual( + m_subp.call_args_list, + [self._useradd2call([user, '-M']), + mock.call(['passwd', '-l', user])]) + + @mock.patch("cloudinit.distros.util.subp") + def test_system_user(self, m_subp): + # system user should have no home and get --system + user = 'foouser' + self.dist.create_user(user, system=True) + self.assertEqual( + m_subp.call_args_list, + [self._useradd2call([user, '--system', '-M']), + mock.call(['passwd', '-l', user])]) + + @mock.patch("cloudinit.distros.util.subp") + def test_explicit_no_home_false(self, m_subp): + user = 'foouser' + self.dist.create_user(user, no_create_home=False) + self.assertEqual( + m_subp.call_args_list, + [self._useradd2call([user, '-m']), + mock.call(['passwd', '-l', user])]) + + @mock.patch("cloudinit.distros.util.subp") + def test_unlocked(self, m_subp): + user = 'foouser' + self.dist.create_user(user, lock_passwd=False) + self.assertEqual( + m_subp.call_args_list, + [self._useradd2call([user, '-m'])]) + + @mock.patch("cloudinit.distros.util.subp") + def test_set_password(self, m_subp): + user = 'foouser' + password = 'passfoo' + self.dist.create_user(user, passwd=password) + self.assertEqual( + m_subp.call_args_list, + [self._useradd2call([user, '--password', password, '-m']), + mock.call(['passwd', '-l', user])]) + + @mock.patch("cloudinit.distros.util.is_group") + @mock.patch("cloudinit.distros.util.subp") + def test_group_added(self, m_subp, m_is_group): + m_is_group.return_value = False + user = 'foouser' + self.dist.create_user(user, groups=['group1']) + expected = [ + mock.call(['groupadd', 'group1']), + self._useradd2call([user, '--groups', 'group1', '-m']), + mock.call(['passwd', '-l', user])] + self.assertEqual(m_subp.call_args_list, expected) + + @mock.patch("cloudinit.distros.util.is_group") + @mock.patch("cloudinit.distros.util.subp") + def test_only_new_group_added(self, m_subp, m_is_group): + ex_groups = ['existing_group'] + groups = ['group1', ex_groups[0]] + m_is_group.side_effect = lambda m: m in ex_groups + user = 'foouser' + self.dist.create_user(user, groups=groups) + expected = [ + mock.call(['groupadd', 'group1']), + self._useradd2call([user, '--groups', ','.join(groups), '-m']), + mock.call(['passwd', '-l', user])] + self.assertEqual(m_subp.call_args_list, expected) + + @mock.patch("cloudinit.distros.util.is_group") + @mock.patch("cloudinit.distros.util.subp") + def test_create_groups_with_whitespace_string(self, m_subp, m_is_group): + # groups supported as a comma delimeted string even with white space + m_is_group.return_value = False + user = 'foouser' + self.dist.create_user(user, groups='group1, group2') + expected = [ + mock.call(['groupadd', 'group1']), + mock.call(['groupadd', 'group2']), + self._useradd2call([user, '--groups', 'group1,group2', '-m']), + mock.call(['passwd', '-l', user])] + self.assertEqual(m_subp.call_args_list, expected) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_distros/test_generic.py b/tests/unittests/test_distros/test_generic.py index 24ad115f..c9be277e 100644 --- a/tests/unittests/test_distros/test_generic.py +++ b/tests/unittests/test_distros/test_generic.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit import distros from cloudinit import util diff --git a/tests/unittests/test_distros/test_hostname.py b/tests/unittests/test_distros/test_hostname.py index 5f28a868..f6d4dbe5 100644 --- a/tests/unittests/test_distros/test_hostname.py +++ b/tests/unittests/test_distros/test_hostname.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import unittest from cloudinit.distros.parsers import hostname @@ -36,3 +38,5 @@ class TestHostnameHelper(unittest.TestCase): bbbbd ''' self.assertEqual(str(hn).strip(), expected_out.strip()) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_distros/test_hosts.py b/tests/unittests/test_distros/test_hosts.py index ab867c6f..8aaa6e48 100644 --- a/tests/unittests/test_distros/test_hosts.py +++ b/tests/unittests/test_distros/test_hosts.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import unittest from cloudinit.distros.parsers import hosts @@ -39,3 +41,5 @@ class TestHostsHelper(unittest.TestCase): eh.del_entries('127.0.0.0') self.assertEqual(eh.get_entry('127.0.0.0'), []) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py index 36eae2dc..bde3bb50 100644 --- a/tests/unittests/test_distros/test_netconfig.py +++ b/tests/unittests/test_distros/test_netconfig.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import os from six import StringIO @@ -379,3 +381,5 @@ ifconfig_vtnet0="DHCP" ''' self.assertCfgEquals(expected_buf, str(write_buf)) self.assertEqual(write_buf.mode, 0o644) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_distros/test_resolv.py b/tests/unittests/test_distros/test_resolv.py index 9402b5ea..6b535a95 100644 --- a/tests/unittests/test_distros/test_resolv.py +++ b/tests/unittests/test_distros/test_resolv.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit.distros.parsers import resolv_conf from cloudinit.distros import rhel_util @@ -65,3 +67,5 @@ class TestResolvHelper(TestCase): self.assertEqual(len(rp.search_domains), 6) self.assertRaises(ValueError, rp.add_search_domain, 'bbb5.y.com') self.assertEqual(len(rp.search_domains), 6) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_distros/test_sysconfig.py b/tests/unittests/test_distros/test_sysconfig.py index 8cb55522..235ecebb 100644 --- a/tests/unittests/test_distros/test_sysconfig.py +++ b/tests/unittests/test_distros/test_sysconfig.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import re from cloudinit.distros.parsers.sys_conf import SysConf @@ -80,3 +82,5 @@ USEMD5=no''' contents = str(conf) self.assertIn("Z=d", contents) self.assertIn("BLAH=b", contents) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_distros/test_user_data_normalize.py b/tests/unittests/test_distros/test_user_data_normalize.py index 33bf922d..88746e0a 100755 --- a/tests/unittests/test_distros/test_user_data_normalize.py +++ b/tests/unittests/test_distros/test_user_data_normalize.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit import distros from cloudinit.distros import ug_util from cloudinit import helpers @@ -361,3 +363,5 @@ class TestUGNormalize(TestCase): mock_subp.assert_any_call(groupcmd) mock_subp.assert_any_call(addcmd, logstring=addcmd) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_ec2_util.py b/tests/unittests/test_ec2_util.py index d6cf17fa..4a33d747 100644 --- a/tests/unittests/test_ec2_util.py +++ b/tests/unittests/test_ec2_util.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from . import helpers from cloudinit import ec2_utils as eu @@ -137,3 +139,5 @@ class TestEc2Util(helpers.HttprettyTestCase): self.assertEqual(2, len(bdm)) self.assertEqual(bdm['ami'], 'sdb') self.assertEqual(bdm['ephemeral0'], 'sdc') + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_filters/test_launch_index.py b/tests/unittests/test_filters/test_launch_index.py index 395713e6..13137f6d 100644 --- a/tests/unittests/test_filters/test_launch_index.py +++ b/tests/unittests/test_filters/test_launch_index.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import copy from .. import helpers @@ -130,3 +132,5 @@ class TestLaunchFilter(helpers.ResourceUsingTestCase): '1': 2, } self.assertCounts(message, expected_counts) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_apt_conf_v1.py b/tests/unittests/test_handler/test_handler_apt_conf_v1.py index 64acc3e0..554277ff 100644 --- a/tests/unittests/test_handler/test_handler_apt_conf_v1.py +++ b/tests/unittests/test_handler/test_handler_apt_conf_v1.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit.config import cc_apt_configure from cloudinit import util diff --git a/tests/unittests/test_handler/test_handler_apt_configure_sources_list_v1.py b/tests/unittests/test_handler/test_handler_apt_configure_sources_list_v1.py index f4411869..f53ddbb2 100644 --- a/tests/unittests/test_handler/test_handler_apt_configure_sources_list_v1.py +++ b/tests/unittests/test_handler/test_handler_apt_configure_sources_list_v1.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + """ test_handler_apt_configure_sources_list Test templating of sources list """ diff --git a/tests/unittests/test_handler/test_handler_apt_configure_sources_list_v3.py b/tests/unittests/test_handler/test_handler_apt_configure_sources_list_v3.py index e53b0450..24e45233 100644 --- a/tests/unittests/test_handler/test_handler_apt_configure_sources_list_v3.py +++ b/tests/unittests/test_handler/test_handler_apt_configure_sources_list_v3.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + """ test_apt_custom_sources_list Test templating of custom sources list """ diff --git a/tests/unittests/test_handler/test_handler_apt_source_v1.py b/tests/unittests/test_handler/test_handler_apt_source_v1.py index ddff4341..12502d05 100644 --- a/tests/unittests/test_handler/test_handler_apt_source_v1.py +++ b/tests/unittests/test_handler/test_handler_apt_source_v1.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + """ test_handler_apt_source_v1 Testing various config variations of the apt_source config This calls all things with v1 format to stress the conversion code on top of diff --git a/tests/unittests/test_handler/test_handler_apt_source_v3.py b/tests/unittests/test_handler/test_handler_apt_source_v3.py index b92a50d7..292d3f59 100644 --- a/tests/unittests/test_handler/test_handler_apt_source_v3.py +++ b/tests/unittests/test_handler/test_handler_apt_source_v3.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + """test_handler_apt_source_v3 Testing various config variations of the apt_source custom config This tries to call all in the new v3 format and cares about new features diff --git a/tests/unittests/test_handler/test_handler_ca_certs.py b/tests/unittests/test_handler/test_handler_ca_certs.py index 5e771731..7cee2c3f 100644 --- a/tests/unittests/test_handler/test_handler_ca_certs.py +++ b/tests/unittests/test_handler/test_handler_ca_certs.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit import cloud from cloudinit.config import cc_ca_certs from cloudinit import helpers @@ -269,3 +271,5 @@ class TestRemoveDefaultCaCerts(TestCase): mock_subp.assert_called_once_with( ('debconf-set-selections', '-'), "ca-certificates ca-certificates/trust_new_crts select no") + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_chef.py b/tests/unittests/test_handler/test_handler_chef.py index 7a1bc317..6a152ea2 100644 --- a/tests/unittests/test_handler/test_handler_chef.py +++ b/tests/unittests/test_handler/test_handler_chef.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import json import logging import os @@ -190,3 +192,5 @@ class TestChef(t_help.FilesystemMockingTestCase): self.assertIn(v_path, content) util.load_file(v_path) self.assertEqual(expected_cert, util.load_file(v_path)) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_debug.py b/tests/unittests/test_handler/test_handler_debug.py index 80708d7b..929f786e 100644 --- a/tests/unittests/test_handler/test_handler_debug.py +++ b/tests/unittests/test_handler/test_handler_debug.py @@ -1,18 +1,6 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2014 Yahoo! Inc. -# -# 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. +# Copyright (C) 2014 Yahoo! Inc. # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit.config import cc_debug @@ -79,3 +67,5 @@ class TestDebug(t_help.FilesystemMockingTestCase): cc_debug.handle('cc_debug', cfg, cc, LOG, []) self.assertRaises(IOError, util.load_file, '/var/log/cloud-init-debug.log') + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_disk_setup.py b/tests/unittests/test_handler/test_handler_disk_setup.py index ddef8d48..227f0497 100644 --- a/tests/unittests/test_handler/test_handler_disk_setup.py +++ b/tests/unittests/test_handler/test_handler_disk_setup.py @@ -1,3 +1,7 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +import random + from cloudinit.config import cc_disk_setup from ..helpers import ExitStack, mock, TestCase @@ -28,3 +32,75 @@ class TestIsDiskUsed(TestCase): self.enumerate_disk.return_value = (mock.MagicMock() for _ in range(1)) self.check_fs.return_value = (mock.MagicMock(), None, mock.MagicMock()) self.assertFalse(cc_disk_setup.is_disk_used(mock.MagicMock())) + + +class TestGetMbrHddSize(TestCase): + + def setUp(self): + super(TestGetMbrHddSize, self).setUp() + self.patches = ExitStack() + self.subp = self.patches.enter_context( + mock.patch.object(cc_disk_setup.util, 'subp')) + + def tearDown(self): + super(TestGetMbrHddSize, self).tearDown() + self.patches.close() + + def _configure_subp_mock(self, hdd_size_in_bytes, sector_size_in_bytes): + def _subp(cmd, *args, **kwargs): + self.assertEqual(3, len(cmd)) + if '--getsize64' in cmd: + return hdd_size_in_bytes, None + elif '--getss' in cmd: + return sector_size_in_bytes, None + raise Exception('Unexpected blockdev command called') + + self.subp.side_effect = _subp + + def _test_for_sector_size(self, sector_size): + size_in_bytes = random.randint(10000, 10000000) * 512 + size_in_sectors = size_in_bytes / sector_size + self._configure_subp_mock(size_in_bytes, sector_size) + self.assertEqual(size_in_sectors, + cc_disk_setup.get_mbr_hdd_size('/dev/sda1')) + + def test_size_for_512_byte_sectors(self): + self._test_for_sector_size(512) + + def test_size_for_1024_byte_sectors(self): + self._test_for_sector_size(1024) + + def test_size_for_2048_byte_sectors(self): + self._test_for_sector_size(2048) + + def test_size_for_4096_byte_sectors(self): + self._test_for_sector_size(4096) + + +class TestGetPartitionMbrLayout(TestCase): + + def test_single_partition_using_boolean(self): + self.assertEqual('0,', + cc_disk_setup.get_partition_mbr_layout(1000, True)) + + def test_single_partition_using_list(self): + disk_size = random.randint(1000000, 1000000000000) + self.assertEqual( + ',,83', + cc_disk_setup.get_partition_mbr_layout(disk_size, [100])) + + def test_half_and_half(self): + disk_size = random.randint(1000000, 1000000000000) + expected_partition_size = int(float(disk_size) / 2) + self.assertEqual( + ',{0},83\n,,83'.format(expected_partition_size), + cc_disk_setup.get_partition_mbr_layout(disk_size, [50, 50])) + + def test_thirds_with_different_partition_type(self): + disk_size = random.randint(1000000, 1000000000000) + expected_partition_size = int(float(disk_size) * 0.33) + self.assertEqual( + ',{0},83\n,,82'.format(expected_partition_size), + cc_disk_setup.get_partition_mbr_layout(disk_size, [33, [66, 82]])) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_growpart.py b/tests/unittests/test_handler/test_handler_growpart.py index e28067de..c5fc8c9b 100644 --- a/tests/unittests/test_handler/test_handler_growpart.py +++ b/tests/unittests/test_handler/test_handler_growpart.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit import cloud from cloudinit.config import cc_growpart from cloudinit import util diff --git a/tests/unittests/test_handler/test_handler_locale.py b/tests/unittests/test_handler/test_handler_locale.py index c91908f4..e9a810c5 100644 --- a/tests/unittests/test_handler/test_handler_locale.py +++ b/tests/unittests/test_handler/test_handler_locale.py @@ -1,20 +1,8 @@ -# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. # -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# Based on test_handler_set_hostname.py -# -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit.config import cc_locale @@ -65,3 +53,5 @@ class TestLocale(t_help.FilesystemMockingTestCase): contents = util.load_file('/etc/sysconfig/language', decode=False) n_cfg = ConfigObj(BytesIO(contents)) self.assertEqual({'RC_LANG': cfg['locale']}, dict(n_cfg)) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_lxd.py b/tests/unittests/test_handler/test_handler_lxd.py index 14366a10..351226bf 100644 --- a/tests/unittests/test_handler/test_handler_lxd.py +++ b/tests/unittests/test_handler/test_handler_lxd.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit.config import cc_lxd from cloudinit.sources import DataSourceNoCloud from cloudinit import (distros, helpers, cloud) @@ -183,3 +185,5 @@ class TestLxd(t_help.TestCase): self.assertEqual( cc_lxd.bridge_to_cmd(data), (None, None)) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_mcollective.py b/tests/unittests/test_handler/test_handler_mcollective.py index c3a5a634..2a9f3823 100644 --- a/tests/unittests/test_handler/test_handler_mcollective.py +++ b/tests/unittests/test_handler/test_handler_mcollective.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit import (cloud, distros, helpers, util) from cloudinit.config import cc_mcollective from cloudinit.sources import DataSourceNoCloud @@ -148,3 +150,5 @@ class TestHandler(t_help.TestCase): self.assertTrue(mock_util.subp.called) self.assertEqual(mock_util.subp.call_args_list[0][0][0], ['service', 'mcollective', 'restart']) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_mounts.py b/tests/unittests/test_handler/test_handler_mounts.py index 355674b2..650ca0ec 100644 --- a/tests/unittests/test_handler/test_handler_mounts.py +++ b/tests/unittests/test_handler/test_handler_mounts.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import os.path import shutil import tempfile @@ -131,3 +133,5 @@ class TestSanitizeDevname(test_helpers.FilesystemMockingTestCase): self.assertIsNone( cc_mounts.sanitize_devname( 'ephemeral0.1', lambda x: disk_path, mock.Mock())) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_ntp.py b/tests/unittests/test_handler/test_handler_ntp.py index 1c7bb06a..ec600077 100644 --- a/tests/unittests/test_handler/test_handler_ntp.py +++ b/tests/unittests/test_handler/test_handler_ntp.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit.config import cc_ntp from cloudinit.sources import DataSourceNone from cloudinit import templater @@ -272,3 +274,5 @@ class TestNtp(FilesystemMockingTestCase): cc_ntp.handle('cc_ntp', {}, cc, LOG, []) self.assertFalse(cc.distro.install_packages.called) self.assertFalse(mock_util.subp.called) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_power_state.py b/tests/unittests/test_handler/test_handler_power_state.py index feff319d..3fd0069d 100644 --- a/tests/unittests/test_handler/test_handler_power_state.py +++ b/tests/unittests/test_handler/test_handler_power_state.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import sys from cloudinit.config import cc_power_state_change as psc @@ -125,3 +127,5 @@ def check_lps_ret(psc_return, mode=None): if len(errs): lines = ["Errors in result: %s" % str(psc_return)] + errs raise Exception('\n'.join(lines)) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_rsyslog.py b/tests/unittests/test_handler/test_handler_rsyslog.py index 38636063..cca06678 100644 --- a/tests/unittests/test_handler/test_handler_rsyslog.py +++ b/tests/unittests/test_handler/test_handler_rsyslog.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import os import shutil import tempfile @@ -172,3 +174,5 @@ class TestRemotesToSyslog(t_help.TestCase): lines = r.splitlines() self.assertEqual(1, len(lines)) self.assertTrue(myline in r.splitlines()) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_seed_random.py b/tests/unittests/test_handler/test_handler_seed_random.py index a0390da9..e5e607fb 100644 --- a/tests/unittests/test_handler/test_handler_seed_random.py +++ b/tests/unittests/test_handler/test_handler_seed_random.py @@ -1,20 +1,12 @@ +# This file is part of cloud-init. See LICENSE file for license information. + # Copyright (C) 2013 Hewlett-Packard Development Company, L.P. # # Author: Juerg Haefliger <juerg.haefliger@hp.com> # # Based on test_handler_set_hostname.py # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit.config import cc_seed_random @@ -225,3 +217,5 @@ def apply_patches(patches): setattr(ref, name, replace) ret.append((ref, name, orig)) return ret + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_set_hostname.py b/tests/unittests/test_handler/test_handler_set_hostname.py index 7effa124..4b18de75 100644 --- a/tests/unittests/test_handler/test_handler_set_hostname.py +++ b/tests/unittests/test_handler/test_handler_set_hostname.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit.config import cc_set_hostname from cloudinit import cloud @@ -70,3 +72,5 @@ class TestHostname(t_help.FilesystemMockingTestCase): cc_set_hostname.handle('cc_set_hostname', cfg, cc, LOG, []) contents = util.load_file("/etc/HOSTNAME") self.assertEqual('blah', contents.strip()) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_snappy.py b/tests/unittests/test_handler/test_handler_snappy.py index e320dd82..edb73d6d 100644 --- a/tests/unittests/test_handler/test_handler_snappy.py +++ b/tests/unittests/test_handler/test_handler_snappy.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit.config.cc_snappy import ( makeop, get_package_ops, render_snap_op) from cloudinit.config.cc_snap_config import ( @@ -595,3 +597,5 @@ def apply_patches(patches): setattr(ref, name, replace) ret.append((ref, name, orig)) return ret + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_spacewalk.py b/tests/unittests/test_handler/test_handler_spacewalk.py index 44f95e4c..28b5892a 100644 --- a/tests/unittests/test_handler/test_handler_spacewalk.py +++ b/tests/unittests/test_handler/test_handler_spacewalk.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit.config import cc_spacewalk from cloudinit import util @@ -40,3 +42,5 @@ class TestSpacewalk(helpers.TestCase): '--profilename', 'test', '--sslCACert', cc_spacewalk.def_ca_cert_path, ], capture=False) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_timezone.py b/tests/unittests/test_handler/test_handler_timezone.py index b7e6b03d..c30fbdfe 100644 --- a/tests/unittests/test_handler/test_handler_timezone.py +++ b/tests/unittests/test_handler/test_handler_timezone.py @@ -1,20 +1,8 @@ -# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. +# Copyright (C) 2013 Hewlett-Packard Development Company, L.P. # -# Author: Juerg Haefliger <juerg.haefliger@hp.com> +# Author: Juerg Haefliger <juerg.haefliger@hp.com> # -# Based on test_handler_set_hostname.py -# -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit.config import cc_timezone @@ -74,3 +62,5 @@ class TestTimezone(t_help.FilesystemMockingTestCase): contents = util.load_file('/etc/localtime') self.assertEqual(dummy_contents, contents.strip()) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_handler/test_handler_write_files.py b/tests/unittests/test_handler/test_handler_write_files.py index 466e45f8..fb252d1d 100644 --- a/tests/unittests/test_handler/test_handler_write_files.py +++ b/tests/unittests/test_handler/test_handler_write_files.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit.config.cc_write_files import write_files from cloudinit import log as logging from cloudinit import util diff --git a/tests/unittests/test_handler/test_handler_yum_add_repo.py b/tests/unittests/test_handler/test_handler_yum_add_repo.py index 28b060f8..3feba86c 100644 --- a/tests/unittests/test_handler/test_handler_yum_add_repo.py +++ b/tests/unittests/test_handler/test_handler_yum_add_repo.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit.config import cc_yum_add_repo from cloudinit import util @@ -66,3 +68,5 @@ class TestConfig(helpers.FilesystemMockingTestCase): } } self.assertEqual(expected, dict(contents)) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_helpers.py b/tests/unittests/test_helpers.py index 943a5723..955f8dfa 100644 --- a/tests/unittests/test_helpers.py +++ b/tests/unittests/test_helpers.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + """Tests of the built-in user data handlers.""" import os @@ -31,3 +33,5 @@ class TestPaths(test_helpers.ResourceUsingTestCase): mypaths = self.getCloudPaths(myds) self.assertEqual(None, mypaths.get_ipath()) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_merging.py b/tests/unittests/test_merging.py index a33ec184..0658b6b4 100644 --- a/tests/unittests/test_merging.py +++ b/tests/unittests/test_merging.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from . import helpers from cloudinit.handlers import cloud_config @@ -255,3 +257,5 @@ class TestSimpleRun(helpers.ResourceUsingTestCase): c = _old_mergedict(a, b) d = util.mergemanydict([a, b]) self.assertEqual(c, d) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py index 78c080ca..1090282a 100644..100755 --- a/tests/unittests/test_net.py +++ b/tests/unittests/test_net.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit import net from cloudinit.net import cmdline from cloudinit.net import eni @@ -8,6 +10,8 @@ from cloudinit import util from .helpers import dir2dict from .helpers import mock +from .helpers import populate_dir +from .helpers import TempDirTestCase from .helpers import TestCase import base64 @@ -54,22 +58,9 @@ DHCP_EXPECTED_1 = { } DHCP6_CONTENT_1 = """ -DEVICE=eno1 -HOSTNAME= -DNSDOMAIN= -reason='PREINIT' -interface='eno1' -DEVICE=eno1 +DEVICE6=eno1 HOSTNAME= DNSDOMAIN= -reason='FAIL' -interface='eno1' -DEVICE=eno1 -HOSTNAME= -DNSDOMAIN= -reason='PREINIT6' -interface='eno1' -DEVICE=eno1 IPV6PROTO=dhcp6 IPV6ADDR=2001:67c:1562:8010:0:1:: IPV6NETMASK=64 @@ -77,11 +68,6 @@ IPV6DNS0=2001:67c:1562:8010::2:1 IPV6DOMAINSEARCH= HOSTNAME= DNSDOMAIN= -reason='BOUND6' -interface='eno1' -new_ip6_address='2001:67c:1562:8010:0:1::' -new_ip6_prefixlen='64' -new_dhcp6_name_servers='2001:67c:1562:8010::2:1' """ DHCP6_EXPECTED_1 = { @@ -461,7 +447,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true } -def _setup_test(tmp_dir, mock_get_devicelist, mock_sys_netdev_info, +def _setup_test(tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path): mock_get_devicelist.return_value = ['eth1000'] dev_characteristics = { @@ -474,10 +460,12 @@ def _setup_test(tmp_dir, mock_get_devicelist, mock_sys_netdev_info, } } - def netdev_info(name, field): - return dev_characteristics[name][field] + def fake_read(devname, path, translate=None, + on_enoent=None, on_keyerror=None, + on_einval=None): + return dev_characteristics[devname][path] - mock_sys_netdev_info.side_effect = netdev_info + mock_read_sys_net.side_effect = fake_read def sys_dev_path(devname, path=""): return tmp_dir + devname + "/" + path @@ -493,15 +481,15 @@ def _setup_test(tmp_dir, mock_get_devicelist, mock_sys_netdev_info, class TestSysConfigRendering(TestCase): @mock.patch("cloudinit.net.sys_dev_path") - @mock.patch("cloudinit.net.sys_netdev_info") + @mock.patch("cloudinit.net.read_sys_net") @mock.patch("cloudinit.net.get_devicelist") def test_default_generation(self, mock_get_devicelist, - mock_sys_netdev_info, + mock_read_sys_net, mock_sys_dev_path): tmp_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, tmp_dir) _setup_test(tmp_dir, mock_get_devicelist, - mock_sys_netdev_info, mock_sys_dev_path) + mock_read_sys_net, mock_sys_dev_path) network_cfg = net.generate_fallback_config() ns = network_state.parse_net_config_data(network_cfg, @@ -550,15 +538,15 @@ USERCTL=no class TestEniNetRendering(TestCase): @mock.patch("cloudinit.net.sys_dev_path") - @mock.patch("cloudinit.net.sys_netdev_info") + @mock.patch("cloudinit.net.read_sys_net") @mock.patch("cloudinit.net.get_devicelist") def test_default_generation(self, mock_get_devicelist, - mock_sys_netdev_info, + mock_read_sys_net, mock_sys_dev_path): tmp_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, tmp_dir) _setup_test(tmp_dir, mock_get_devicelist, - mock_sys_netdev_info, mock_sys_dev_path) + mock_read_sys_net, mock_sys_dev_path) network_cfg = net.generate_fallback_config() ns = network_state.parse_net_config_data(network_cfg, @@ -677,6 +665,66 @@ class TestCmdlineConfigParsing(TestCase): self.assertEqual(found, self.simple_cfg) +class TestCmdlineReadKernelConfig(TempDirTestCase): + macs = { + 'eth0': '14:02:ec:42:48:00', + 'eno1': '14:02:ec:42:48:01', + } + + def test_ip_cmdline_read_kernel_cmdline_ip(self): + content = {'net-eth0.conf': DHCP_CONTENT_1} + populate_dir(self.tmp, content) + files = [os.path.join(self.tmp, k) for k in content.keys()] + found = cmdline.read_kernel_cmdline_config( + files=files, cmdline='foo ip=dhcp', mac_addrs=self.macs) + exp1 = copy.deepcopy(DHCP_EXPECTED_1) + exp1['mac_address'] = self.macs['eth0'] + self.assertEqual(found['version'], 1) + self.assertEqual(found['config'], [exp1]) + + def test_ip_cmdline_read_kernel_cmdline_ip6(self): + content = {'net6-eno1.conf': DHCP6_CONTENT_1} + populate_dir(self.tmp, content) + files = [os.path.join(self.tmp, k) for k in content.keys()] + found = cmdline.read_kernel_cmdline_config( + files=files, cmdline='foo ip6=dhcp root=/dev/sda', + mac_addrs=self.macs) + self.assertEqual( + found, + {'version': 1, 'config': [ + {'type': 'physical', 'name': 'eno1', + 'mac_address': self.macs['eno1'], + 'subnets': [ + {'dns_nameservers': ['2001:67c:1562:8010::2:1'], + 'control': 'manual', 'type': 'dhcp6', 'netmask': '64'}]}]}) + + def test_ip_cmdline_read_kernel_cmdline_none(self): + # if there is no ip= or ip6= on cmdline, return value should be None + content = {'net6-eno1.conf': DHCP6_CONTENT_1} + populate_dir(self.tmp, content) + files = [os.path.join(self.tmp, k) for k in content.keys()] + found = cmdline.read_kernel_cmdline_config( + files=files, cmdline='foo root=/dev/sda', mac_addrs=self.macs) + self.assertEqual(found, None) + + def test_ip_cmdline_both_ip_ip6(self): + content = {'net-eth0.conf': DHCP_CONTENT_1, + 'net6-eth0.conf': DHCP6_CONTENT_1.replace('eno1', 'eth0')} + populate_dir(self.tmp, content) + files = [os.path.join(self.tmp, k) for k in sorted(content.keys())] + found = cmdline.read_kernel_cmdline_config( + files=files, cmdline='foo ip=dhcp ip6=dhcp', mac_addrs=self.macs) + + eth0 = copy.deepcopy(DHCP_EXPECTED_1) + eth0['mac_address'] = self.macs['eth0'] + eth0['subnets'].append( + {'control': 'manual', 'type': 'dhcp6', + 'netmask': '64', 'dns_nameservers': ['2001:67c:1562:8010::2:1']}) + expected = [eth0] + self.assertEqual(found['version'], 1) + self.assertEqual(found['config'], expected) + + class TestEniRoundTrip(TestCase): def setUp(self): super(TestCase, self).setUp() @@ -723,6 +771,52 @@ class TestEniRoundTrip(TestCase): entry['expected_eni'].splitlines(), files['/etc/network/interfaces'].splitlines()) + def test_routes_rendered(self): + # as reported in bug 1649652 + conf = [ + {'name': 'eth0', 'type': 'physical', + 'subnets': [{ + 'address': '172.23.31.42/26', + 'dns_nameservers': [], 'gateway': '172.23.31.2', + 'type': 'static'}]}, + {'type': 'route', 'id': 4, + 'metric': 0, 'destination': '10.0.0.0/12', + 'gateway': '172.23.31.1'}, + {'type': 'route', 'id': 5, + 'metric': 0, 'destination': '192.168.2.0/16', + 'gateway': '172.23.31.1'}, + {'type': 'route', 'id': 6, + 'metric': 1, 'destination': '10.0.200.0/16', + 'gateway': '172.23.31.1'}, + ] + + files = self._render_and_read( + network_config={'config': conf, 'version': 1}) + expected = [ + 'auto lo', + 'iface lo inet loopback', + 'auto eth0', + 'iface eth0 inet static', + ' address 172.23.31.42/26', + ' gateway 172.23.31.2', + ('post-up route add -net 10.0.0.0 netmask 255.240.0.0 gw ' + '172.23.31.1 metric 0 || true'), + ('pre-down route del -net 10.0.0.0 netmask 255.240.0.0 gw ' + '172.23.31.1 metric 0 || true'), + ('post-up route add -net 192.168.2.0 netmask 255.255.0.0 gw ' + '172.23.31.1 metric 0 || true'), + ('pre-down route del -net 192.168.2.0 netmask 255.255.0.0 gw ' + '172.23.31.1 metric 0 || true'), + ('post-up route add -net 10.0.200.0 netmask 255.255.0.0 gw ' + '172.23.31.1 metric 1 || true'), + ('pre-down route del -net 10.0.200.0 netmask 255.255.0.0 gw ' + '172.23.31.1 metric 1 || true'), + ] + found = files['/etc/network/interfaces'].splitlines() + + self.assertEqual( + expected, [line for line in found if line]) + def _gzip_data(data): with io.BytesIO() as iobuf: @@ -730,3 +824,5 @@ def _gzip_data(data): gzfp.write(data) gzfp.close() return iobuf.getvalue() + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_pathprefix2dict.py b/tests/unittests/test_pathprefix2dict.py index 38fd75b6..a4ae284f 100644 --- a/tests/unittests/test_pathprefix2dict.py +++ b/tests/unittests/test_pathprefix2dict.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit import util from .helpers import TestCase, populate_dir diff --git a/tests/unittests/test_registry.py b/tests/unittests/test_registry.py index bcf01475..acf0bf4f 100644 --- a/tests/unittests/test_registry.py +++ b/tests/unittests/test_registry.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from cloudinit.registry import DictRegistry from .helpers import (mock, TestCase) @@ -26,3 +28,5 @@ class TestDictRegistry(TestCase): registry.register_item(item_key, mock.Mock()) self.assertRaises(ValueError, registry.register_item, item_key, mock.Mock()) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_reporting.py b/tests/unittests/test_reporting.py index 20ca23df..f3b8f992 100644 --- a/tests/unittests/test_reporting.py +++ b/tests/unittests/test_reporting.py @@ -1,7 +1,6 @@ # Copyright 2015 Canonical Ltd. -# This file is part of cloud-init. See LICENCE file for license information. # -# vi: ts=4 expandtab +# This file is part of cloud-init. See LICENSE file for license information. from cloudinit import reporting from cloudinit.reporting import events @@ -369,3 +368,5 @@ class TestReportingEventStack(TestCase): class TestStatusAccess(TestCase): def test_invalid_status_access_raises_value_error(self): self.assertRaises(AttributeError, getattr, events.status, "BOGUS") + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_rh_subscription.py b/tests/unittests/test_rh_subscription.py index 891dbe77..ca14cd46 100644 --- a/tests/unittests/test_rh_subscription.py +++ b/tests/unittests/test_rh_subscription.py @@ -1,14 +1,6 @@ -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. + +"""Tests for registering RHEL subscription via rh_subscription.""" import logging @@ -83,8 +75,8 @@ class GoodTests(TestCase): ''' call_lists = [] call_lists.append(['attach', '--pool=pool1', '--pool=pool3']) - call_lists.append(['repos', '--enable=repo2', '--enable=repo3', - '--disable=repo5']) + call_lists.append(['repos', '--disable=repo5', '--enable=repo2', + '--enable=repo3']) call_lists.append(['attach', '--auto', '--servicelevel=self-support']) self.SM.log_success = mock.MagicMock() reg = "The system has been registered with ID:" \ @@ -224,3 +216,5 @@ class TestBadInput(TestCase): self.SM._sub_man_cli.assert_called_with(['identity']) self.assertEqual(self.SM.log_warn.call_count, 4) self.assertEqual(self.SM._sub_man_cli.call_count, 1) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_runs/test_merge_run.py b/tests/unittests/test_runs/test_merge_run.py index ce43798e..65895273 100644 --- a/tests/unittests/test_runs/test_merge_run.py +++ b/tests/unittests/test_runs/test_merge_run.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import os import shutil import tempfile @@ -52,3 +54,5 @@ class TestMergeRun(helpers.FilesystemMockingTestCase): self.assertIn('write-files', which_ran) contents = util.load_file('/etc/blah.ini') self.assertEqual(contents, 'blah') + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_runs/test_simple_run.py b/tests/unittests/test_runs/test_simple_run.py index 07e7b1a8..31324204 100644 --- a/tests/unittests/test_runs/test_simple_run.py +++ b/tests/unittests/test_runs/test_simple_run.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + import os import shutil import tempfile @@ -79,3 +81,5 @@ class TestSimpleRun(helpers.FilesystemMockingTestCase): self.assertIn('write-files', which_ran) contents = util.load_file('/etc/blah.ini') self.assertEqual(contents, 'blah') + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_sshutil.py b/tests/unittests/test_sshutil.py index 9aeb1cde..55971b5e 100644 --- a/tests/unittests/test_sshutil.py +++ b/tests/unittests/test_sshutil.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from mock import patch from . import helpers as test_helpers diff --git a/tests/unittests/test_templating.py b/tests/unittests/test_templating.py index 94b6e061..4e627826 100644 --- a/tests/unittests/test_templating.py +++ b/tests/unittests/test_templating.py @@ -1,20 +1,8 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2014 Yahoo! Inc. -# -# Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Copyright (C) 2014 Yahoo! Inc. # -# 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. +# Author: Joshua Harlow <harlowja@yahoo-inc.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. from __future__ import print_function @@ -117,3 +105,5 @@ $a,$b''' {'mirror': mirror, 'codename': codename}) self.assertEqual(ex_data, out_data) + +# vi: ts=4 expandtab diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py index f6a8ab75..ab74311e 100644 --- a/tests/unittests/test_util.py +++ b/tests/unittests/test_util.py @@ -1,3 +1,5 @@ +# This file is part of cloud-init. See LICENSE file for license information. + from __future__ import print_function import logging @@ -611,4 +613,73 @@ class TestEncode(helpers.TestCase): text = util.decode_binary(blob) self.assertEqual(text, blob) + +class TestProcessExecutionError(helpers.TestCase): + + template = ('{description}\n' + 'Command: {cmd}\n' + 'Exit code: {exit_code}\n' + 'Reason: {reason}\n' + 'Stdout: {stdout}\n' + 'Stderr: {stderr}') + empty_attr = '-' + empty_description = 'Unexpected error while running command.' + + def test_pexec_error_indent_text(self): + error = util.ProcessExecutionError() + msg = 'abc\ndef' + formatted = 'abc\n{0}def'.format(' ' * 4) + self.assertEqual(error._indent_text(msg, indent_level=4), formatted) + self.assertEqual(error._indent_text(msg.encode(), indent_level=4), + formatted.encode()) + self.assertIsInstance( + error._indent_text(msg.encode()), type(msg.encode())) + + def test_pexec_error_type(self): + self.assertIsInstance(util.ProcessExecutionError(), IOError) + + def test_pexec_error_empty_msgs(self): + error = util.ProcessExecutionError() + self.assertTrue(all(attr == self.empty_attr for attr in + (error.stderr, error.stdout, error.reason))) + self.assertEqual(error.description, self.empty_description) + self.assertEqual(str(error), self.template.format( + description=self.empty_description, exit_code=self.empty_attr, + reason=self.empty_attr, stdout=self.empty_attr, + stderr=self.empty_attr, cmd=self.empty_attr)) + + def test_pexec_error_single_line_msgs(self): + stdout_msg = 'out out' + stderr_msg = 'error error' + cmd = 'test command' + exit_code = 3 + error = util.ProcessExecutionError( + stdout=stdout_msg, stderr=stderr_msg, exit_code=3, cmd=cmd) + self.assertEqual(str(error), self.template.format( + description=self.empty_description, stdout=stdout_msg, + stderr=stderr_msg, exit_code=str(exit_code), + reason=self.empty_attr, cmd=cmd)) + + def test_pexec_error_multi_line_msgs(self): + # make sure bytes is converted handled properly when formatting + stdout_msg = 'multi\nline\noutput message'.encode() + stderr_msg = 'multi\nline\nerror message\n\n\n' + error = util.ProcessExecutionError( + stdout=stdout_msg, stderr=stderr_msg) + self.assertEqual( + str(error), + '\n'.join(( + '{description}', + 'Command: {empty_attr}', + 'Exit code: {empty_attr}', + 'Reason: {empty_attr}', + 'Stdout: multi', + ' line', + ' output message', + 'Stderr: multi', + ' line', + ' error message', + )).format(description=self.empty_description, + empty_attr=self.empty_attr)) + # vi: ts=4 expandtab diff --git a/tests/unittests/test_vmware_config_file.py b/tests/unittests/test_vmware_config_file.py index d5c7367b..18475f10 100644 --- a/tests/unittests/test_vmware_config_file.py +++ b/tests/unittests/test_vmware_config_file.py @@ -1,21 +1,9 @@ -# vi: ts=4 expandtab -# -# Copyright (C) 2015 Canonical Ltd. -# Copyright (C) 2016 VMware INC. -# -# Author: Sankar Tanguturi <stanguturi@vmware.com> +# Copyright (C) 2015 Canonical Ltd. +# Copyright (C) 2016 VMware INC. # -# 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. +# Author: Sankar Tanguturi <stanguturi@vmware.com> # -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. import logging import sys @@ -101,3 +89,5 @@ class TestVmwareConfigFile(unittest.TestCase): self.assertEqual('NIC1', nics[0].name, "nic0") self.assertEqual('00:50:56:a6:8c:08', nics[0].mac, "mac0") self.assertEqual(BootProtoEnum.DHCP, nics[0].bootProto, "bootproto0") + +# vi: ts=4 expandtab diff --git a/tools/Z99-cloud-locale-test.sh b/tools/Z99-cloud-locale-test.sh index 8e0469ed..5912bae2 100755 --- a/tools/Z99-cloud-locale-test.sh +++ b/tools/Z99-cloud-locale-test.sh @@ -1,13 +1,14 @@ #!/bin/sh -# vi: ts=4 noexpandtab +# Copyright (C) 2012, Canonical Group, Ltd. # # Author: Ben Howard <ben.howard@canonical.com> # Author: Scott Moser <scott.moser@ubuntu.com> # (c) 2012, Canonical Group, Ltd. # +# This file is part of cloud-init. See LICENSE file for license information. + # Purpose: Detect invalid locale settings and inform the user # of how to fix them. -# locale_warn() { local bad_names="" bad_lcs="" key="" val="" var="" vars="" bad_kv="" @@ -96,3 +97,4 @@ locale_warn() { locale 2>&1 | locale_warn unset locale_warn +# vi: ts=4 noexpandtab diff --git a/tools/cloud-init-per b/tools/cloud-init-per index 5d9a2864..7d6754b6 100755 --- a/tools/cloud-init-per +++ b/tools/cloud-init-per @@ -1,4 +1,5 @@ #!/bin/sh +# This file is part of cloud-init. See LICENSE file for license information. DATA_PRE="/var/lib/cloud/sem/bootper" INST_PRE="/var/lib/cloud/instance/sem/bootper" diff --git a/tools/hacking.py b/tools/hacking.py index 2d366a0a..6c320935 100755 --- a/tools/hacking.py +++ b/tools/hacking.py @@ -1,6 +1,4 @@ #!/usr/bin/env python -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - # Copyright (c) 2012, Cloudscaling # All Rights Reserved. # @@ -169,3 +167,5 @@ if __name__ == "__main__": if len(_missingImport) > 0: print >> sys.stderr, ("%i imports missing in this test environment" % len(_missingImport)) + +# vi: ts=4 expandtab diff --git a/tools/hook-dhclient b/tools/hook-dhclient index 6a4626c6..02122f37 100755 --- a/tools/hook-dhclient +++ b/tools/hook-dhclient @@ -1,6 +1,9 @@ #!/bin/sh +# This file is part of cloud-init. See LICENSE file for license information. + # This script writes DHCP lease information into the cloud-init run directory # It is sourced, not executed. For more information see dhclient-script(8). + is_azure() { local dmi_path="/sys/class/dmi/id/board_vendor" vendor="" if [ -e "$dmi_path" ] && read vendor < "$dmi_path"; then diff --git a/tools/hook-network-manager b/tools/hook-network-manager index 98a36c8a..67d9044a 100755 --- a/tools/hook-network-manager +++ b/tools/hook-network-manager @@ -1,4 +1,6 @@ #!/bin/sh +# This file is part of cloud-init. See LICENSE file for license information. + # This script hooks into NetworkManager(8) via its scripts # arguments are 'interface-name' and 'action' # diff --git a/tools/hook-rhel.sh b/tools/hook-rhel.sh index 8232414c..513a5515 100755 --- a/tools/hook-rhel.sh +++ b/tools/hook-rhel.sh @@ -1,4 +1,6 @@ #!/bin/sh +# This file is part of cloud-init. See LICENSE file for license information. + # Current versions of RHEL and CentOS do not honor the directory # /etc/dhcp/dhclient-exit-hooks.d so this file can be placed in # /etc/dhcp/dhclient.d instead diff --git a/tools/make-mime.py b/tools/make-mime.py index 72b29fb9..12727126 100755 --- a/tools/make-mime.py +++ b/tools/make-mime.py @@ -58,3 +58,5 @@ def main(): if __name__ == '__main__': sys.exit(main()) + +# vi: ts=4 expandtab diff --git a/tools/mock-meta.py b/tools/mock-meta.py index 1c746f17..d74f9e31 100755 --- a/tools/mock-meta.py +++ b/tools/mock-meta.py @@ -452,3 +452,5 @@ def run_server(): if __name__ == '__main__': run_server() + +# vi: ts=4 expandtab diff --git a/tools/motd-hook b/tools/motd-hook index 8c482e8c..73d9792c 100755 --- a/tools/motd-hook +++ b/tools/motd-hook @@ -1,23 +1,11 @@ #!/bin/sh +# Copyright (C) 2010 Canonical Ltd. # -# 92-ec2-upgrade-available - update-motd script +# Authors: Scott Moser <smoser@ubuntu.com> # -# Copyright (C) 2010 Canonical Ltd. -# -# Authors: Scott Moser <smoser@ubuntu.com> -# -# 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, version 3 of the License. -# -# 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 <http://www.gnu.org/licenses/>. +# This file is part of cloud-init. See LICENSE file for license information. +# 92-ec2-upgrade-available - update-motd script # Determining if updates are available is possibly slow. # a cronjob runs occasioinally and updates a file with information diff --git a/tools/read-dependencies b/tools/read-dependencies index 9fc503eb..f4349055 100755 --- a/tools/read-dependencies +++ b/tools/read-dependencies @@ -39,3 +39,5 @@ with open(os.path.join(topd, reqfile), "r") as fp: print(dep) sys.exit(0) + +# vi: ts=4 expandtab diff --git a/tools/read-version b/tools/read-version index c10f9b46..3b30b497 100755 --- a/tools/read-version +++ b/tools/read-version @@ -99,3 +99,5 @@ else: sys.stdout.write(release + "\n") sys.exit(0) + +# vi: ts=4 expandtab diff --git a/tools/uncloud-init b/tools/uncloud-init index 2574d482..217371cc 100755 --- a/tools/uncloud-init +++ b/tools/uncloud-init @@ -1,5 +1,5 @@ #!/bin/sh -# vi: ts=4 noexpandtab +# This file is part of cloud-init. See LICENSE file for license information. # This script is meant to "kvmify" an image. Its not meant to be # terribly robust, or a good idea to ever run in a "real image". @@ -139,3 +139,4 @@ grep -q vga16fb /etc/modprobe.d/blacklist.conf || { #fi doexec "$@" +# vi: ts=4 noexpandtab diff --git a/tools/validate-yaml.py b/tools/validate-yaml.py index ed9037d9..d8bbcfcb 100755 --- a/tools/validate-yaml.py +++ b/tools/validate-yaml.py @@ -12,8 +12,8 @@ if __name__ == "__main__": for fn in sys.argv[1:]: sys.stdout.write("%s" % (fn)) try: - fh = open(fn, 'r') - yaml.safe_load(fh.read()) + fh = open(fn, 'rb') + yaml.safe_load(fh.read().decode('utf-8')) fh.close() sys.stdout.write(" - ok\n") except Exception as e: @@ -23,3 +23,5 @@ if __name__ == "__main__": sys.exit(1) else: sys.exit(0) + +# vi: ts=4 expandtab diff --git a/tools/write-ssh-key-fingerprints b/tools/write-ssh-key-fingerprints index 6c3451fd..2a3dca7c 100755 --- a/tools/write-ssh-key-fingerprints +++ b/tools/write-ssh-key-fingerprints @@ -1,4 +1,5 @@ #!/bin/sh +# This file is part of cloud-init. See LICENSE file for license information. logger_opts="-p user.info -t ec2" @@ -3,7 +3,7 @@ envlist = py27, py3, flake8, xenial recreate = True [testenv] -commands = python -m nose {posargs:tests} +commands = python -m nose {posargs:tests/unittests} deps = -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt setenv = @@ -19,17 +19,18 @@ setenv = [testenv:py3] basepython = python3 -commands = {envpython} -m nose \ - {posargs:--with-coverage --cover-erase \ - --cover-branches --cover-package=cloudinit --cover-inclusive} +commands = {envpython} -m nose {posargs:--with-coverage \ + --cover-erase --cover-branches --cover-inclusive \ + --cover-package=cloudinit tests/unittests} [testenv:py26] -commands = nosetests {posargs:tests} +commands = nosetests {posargs:tests/unittests} setenv = LC_ALL = C [flake8] -ignore=H404,H405,H105,H301,H104,H403,H101 +#H102 Apache 2.0 license header not found +ignore=H404,H405,H105,H301,H104,H403,H101,H102 exclude = .venv,.tox,dist,doc,*egg,.git,build,tools [testenv:doc] |