From e1ddddf2a0f81cdab84deeecec3e068d333b6ce8 Mon Sep 17 00:00:00 2001 From: Micah Date: Tue, 24 May 2016 10:19:40 -0400 Subject: Squashed 'puppet/modules/backupninja/' content from commit 5268a87 git-subtree-dir: puppet/modules/backupninja git-subtree-split: 5268a87c329f895017f8ea6c6abc377a4f9a6a77 --- LICENSE | 674 +++++++++++++++++++++ README | 202 ++++++ files/checkbackups.pl | 194 ++++++ files/nagios_plugins/duplicity/README.md | 24 + .../duplicity/backupninja_duplicity_freshness.sh | 268 ++++++++ .../duplicity/check_backupninja_duplicity.py | 123 ++++ manifests/cron.pp | 17 + manifests/duplicity.pp | 147 +++++ manifests/generate_sshkey.pp | 33 + manifests/init.pp | 52 ++ manifests/key.pp | 41 ++ manifests/labelmount.pp | 62 ++ manifests/maildir.pp | 43 ++ manifests/mysql.pp | 38 ++ manifests/nagios_plugin/duplicity.pp | 45 ++ manifests/pgsql.pp | 27 + manifests/rdiff.pp | 109 ++++ manifests/rsync.pp | 128 ++++ manifests/server.pp | 147 +++++ manifests/sh.pp | 25 + manifests/svn.pp | 28 + manifests/sys.pp | 45 ++ templates/backupninja.conf.erb | 25 + templates/backupninja.cron.erb | 6 + templates/dup.conf.erb | 46 ++ templates/labelmount.conf.erb | 2 + templates/labelmount.handler | 17 + templates/maildir.conf.erb | 14 + templates/mysql.conf.erb | 25 + templates/pgsql.conf.erb | 13 + templates/rdiff.conf.erb | 38 ++ templates/rsync.conf.erb | 49 ++ templates/sh.conf.erb | 10 + templates/svn.conf.erb | 10 + templates/sys.conf.erb | 18 + templates/umount.conf.erb | 1 + templates/umount.handler | 15 + 37 files changed, 2761 insertions(+) create mode 100644 LICENSE create mode 100644 README create mode 100755 files/checkbackups.pl create mode 100644 files/nagios_plugins/duplicity/README.md create mode 100644 files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh create mode 100644 files/nagios_plugins/duplicity/check_backupninja_duplicity.py create mode 100644 manifests/cron.pp create mode 100644 manifests/duplicity.pp create mode 100644 manifests/generate_sshkey.pp create mode 100644 manifests/init.pp create mode 100644 manifests/key.pp create mode 100644 manifests/labelmount.pp create mode 100644 manifests/maildir.pp create mode 100644 manifests/mysql.pp create mode 100644 manifests/nagios_plugin/duplicity.pp create mode 100644 manifests/pgsql.pp create mode 100644 manifests/rdiff.pp create mode 100644 manifests/rsync.pp create mode 100644 manifests/server.pp create mode 100644 manifests/sh.pp create mode 100644 manifests/svn.pp create mode 100644 manifests/sys.pp create mode 100644 templates/backupninja.conf.erb create mode 100644 templates/backupninja.cron.erb create mode 100644 templates/dup.conf.erb create mode 100644 templates/labelmount.conf.erb create mode 100644 templates/labelmount.handler create mode 100644 templates/maildir.conf.erb create mode 100644 templates/mysql.conf.erb create mode 100644 templates/pgsql.conf.erb create mode 100644 templates/rdiff.conf.erb create mode 100644 templates/rsync.conf.erb create mode 100644 templates/sh.conf.erb create mode 100644 templates/svn.conf.erb create mode 100644 templates/sys.conf.erb create mode 100644 templates/umount.conf.erb create mode 100644 templates/umount.handler diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README b/README new file mode 100644 index 00000000..42a8bfe2 --- /dev/null +++ b/README @@ -0,0 +1,202 @@ +Backupninja Module +------------------- + +This module helps you configure all of your backups with puppet, using +backupninja! + +!! UPGRADE NOTICE !! + +If you were previously using this module, some pieces have changed, +and you need to carefully change your use of them, or you will find +your backups could stop working or get duplicated. + +The backupninja::client class has been renamed to backupninja, and is +now *required* in all node manifests. Make sure the backupninja class +is now declared in all your node manifests! This new class now defines +defaults which were previously provided by backupninja::client::defaults, +and can now be overridden thanks to the brand new technology of class +parameters. This class also manages the backupninja configuration file, +replacing the backupninja::config ressource. + +The backupninja::server class now takes parameters, replacing several +global variables such as $backupdir, $backupserver_tag and +$nagios_server. The $manage_nagios parameter also replaces the +$use_nagios global. + +As for handlers, they don't include the backupninja::client anymore and +now read several default values from the backupninja base class. The +$installkey parameter used in several handlers has been renamed to +$keymanage, to keep in line with the base class parameter. + +If you were using the rdiff-backup handler, you need to read the +following section carefully. + +Changes to the rdiff-backup handler +----------------------------------- + +You will need to make sure you change all of your "$directory" +parameters to be "$home" instead, and on your backupserver you will need +to move all of your backups into "$home"/rdiff-backup. Previously, they +were put in "$directory", which doubled as the home for the user that +was created. This caused problems with rdiff-backup because of dot files +and other things which were not part of any rdiff-backup. + +The rdiff resource name is now used as the subdirectory where rdiff +backups are sent. This was previously hardcoded to "rdiff-backup", but +in order to support multiple rdiff backups per host, we now use the +resource name. So if you were using the following resource: + + backupninja::rdiff { 'main': } + +You will want to use the following resource: + + backupninja::rdiff { 'rdiff-backup': } + file { '/etc/backup.d/90_main.rdiff': ensure => absent; } + +Otherwise your backups may be duplicated! + +Changes to nagios integration +----------------------------- + +The default nagios passive service name has changed from "backups" to +"backups-${name}". If you want it to be automatically created on your +nagios host, you will need to set $backupninja::manage_nagios to true. +on the client. + +Use the following resource to remove the old "backups" passive service. + + nagios::service { 'backups': ensure => absent } + +Getting started +--------------- + +This module requires Puppet versions 2.7 and up. + +An up-to-date version of the puppet-stdlib module is also required. + +Configure your backup server +---------------------------- + +Now you will need to configure a backup server by adding the following +to your node definition for that server: + + include backupninja::server + +The default configuration will store backup data in the "/backup" +directory. To change this you may declare the class with a "backupdir" +parameter: + + class { 'backupninja::server': + backupdir => '/mnt/backupdata' + } + +By configuring a backupninja::server, this module will automatically +create sandboxed users on the server for each client for their +backups. + +Configure your backup clients +----------------------------- + +First, you need to include the backupninja class or declare it with +custom parameters: + + class { 'backupninja': + loglvl => 3, + usecolors => false, + reportsuccess => false, + reportwarning => true, + ensure_backupninja_version => '1.0.1-1', + ensure_rdiffbackup_version => '1.2.8-7' + } + +In this case, the module will make sure that the backupninja package +is installed (using puppet's ensure parameter language) and create the +/etc/backupninja.conf configuration file. + +If you need to specify a specific version of either backupninja itself, +or the specific programs that the handler class installs, you can +specify the version you need installed by providing a class parameter, +as shown in the example. + +Configuring handlers +-------------------- + +Depending on which backup method you want to use on your client, you +can simply specify some configuration options for that handler that are +necessary for your client. + +Each handler has its own configuration options necessary to make it +work, each of those are available as puppet parameters. You can see +the handler documentation, or look at the handler puppet files +included in this module to see your different options. + +Included below are some configuration examples for different handlers. + +* An example mysql handler configuration: + +backupninja::mysql { 'all_databases': + user => root, + backupdir => '/var/backups', + compress => true, + sqldump => true +} + +* An example rdiff-backup handler configuration: + +backupninja::rdiff { 'backup_all': + directory => '/media/backupdisk', + include => ['/var/backups', '/home', '/var/lib/dpkg/status'], + exclude => '/home/*/.gnupg' +} + +* A remote rdiff-backup handler: + +backupninja::rdiff { 'main': + host => 'backup.example.com', + type => 'remote', + directory => "/backup/${::fqdn}", + user => "backup-${::hostname}", +} + +Automatic creation of ssh-keys for duplicity +-------------------------------------------- + +backupninja::duplicity can be used to + +- create an ssh keypair for a client +- place the keypair on the puppetmaster in a given location +- place the keypair in /root/.ssh on the client + +i.e.: + + backupninja::duplicity { "duplicity_${::fqdn}": + sshoptions => "-oIdentityFile=/root/.ssh/backupninja_${::hostname}_id_rsa", + desthost => 'HOST', + destdir => "/var/backup/backupninja/${::fqdn}", + destuser => "backupninja_${::hostname}", + encryptkey => 'KEYID', + password => 'PW', + backupkeystore => 'puppet:///keys', + backupkeystorefspath => '/etc/puppet/modules/keys/files', + backupkeydestname => "backupninja_${::hostname}_id_rsa", + createkey => true, + installkey => true, + ... + } + + +Nagios alerts about backup freshness +------------------------------------ + +If you set the $backupninja::server::nagios_server variable to be the +name of your nagios server, then a passive nagios service gets setup so +that the backup server pushes checks, via a cronjob that calls +/usr/local/bin/checkbackups.pl, to the nagios server to alert about +relative backup freshness. + +To use this feature a few pre-requisites are necessary: + + . configure nsca on your backup server (not done via puppet yet) + . configure nsca on your nagios server (not done via puppet yet) + . server backup directories are named after their $fqdn + . backups must be under $home/dup, $home/rdiff-backup depending on method diff --git a/files/checkbackups.pl b/files/checkbackups.pl new file mode 100755 index 00000000..39914469 --- /dev/null +++ b/files/checkbackups.pl @@ -0,0 +1,194 @@ +#!/usr/bin/perl -w + +# This script is designed to check a backup directory populated with +# subdirectories named after hosts, within which there are backups of various +# types. +# +# Example: +# /home/backup: +# foo.example.com +# +# foo.example.com: +# rdiff-backup .ssh +# +# rdiff-backup: +# root home rdiff-backup-data usr var +# +# There are heuristics to determine the backup type. Currently, the following +# types are supported: +# +# rdiff-backup: assumes there is a rdiff-backup/rdiff-backup-data/backup.log file +# duplicity: assumes there is a dup subdirectory, checks the latest file +# dump files: assumes there is a dump subdirectory, checks the latest file +# +# This script returns output suitable for send_nsca to send the results to +# nagios and should therefore be used like this: +# +# checkbackups.sh | send_nsca -H nagios.example.com + +use Getopt::Std; + +# XXX: taken from utils.sh from nagios-plugins-basic +my $STATE_OK=0; +my $STATE_WARNING=1; +my $STATE_CRITICAL=2; +my $STATE_UNKNOWN=3; +my $STATE_DEPENDENT=4; +my %ERRORS=(0=>'OK',1=>'WARNING',2=>'CRITICAL',3=>'UNKNOWN',4=>'DEPENDENT'); + +# gross hack: we look into subdirs to find vservers +my @vserver_dirs = qw{/var/lib/vservers /vservers}; + +our $opt_d = "/backup"; +our $opt_c = 48 * 60 * 60; +our $opt_w = 24 * 60 * 60; +our $opt_v = 0; +our $opt_o; +our $opt_s; + +if (!getopts('d:c:w:s:vo')) { + print < ] [ -c ] [ -w ] [ -o ] [ -s ] [ -v ] +EOF + ; + exit(); +} + +sub check_rdiff { + my ($host, $dir, $optv) = @_; + my $flag="$dir/rdiff-backup-data/backup.log"; + my $extra_msg = ''; + my @vservers; + if (open(FLAG, $flag)) { + while () { + if (/EndTime ([0-9]*).[0-9]* \((.*)\)/) { + $last_bak = $1; + $extra_msg = ' [backup.log]'; + $opt_v && print STDERR "found timestamp $1 ($2) in $flag\n"; + } + } + if (!$last_bak) { + print_status($host, $STATE_UNKNOWN, "cannot parse $flag for a valid timestamp"); + next; + } + } else { + $opt_v && print STDERR "cannot open $flag\n"; + } + close(FLAG); + ($state, $delta) = check_age($last_bak); + $dir =~ /([^\/]+)\/?$/; + $service = "backups-$1"; + print_status($host, $state, "$delta hours old$extra_msg", $service); + foreach my $vserver_dir (@vserver_dirs) { + $vsdir = "$dir/$vserver_dir"; + if (opendir(DIR, $vsdir)) { + @vservers = grep { /^[^\.]/ && -d "$vsdir/$_" } readdir(DIR); + $opt_v && print STDERR "found vservers $vsdir: @vservers\n"; + closedir DIR; + } else { + $opt_v && print STDERR "no vserver in $vsdir\n"; + } + } + my @dom_sufx = split(/\./, $host); + my $dom_sufx = join('.', @dom_sufx[1,-1]); + foreach my $vserver (@vservers) { + print_status("$vserver.$dom_sufx", $state, "$delta hours old$extra_msg, same as parent: $host"); + } +} + +sub check_age { + my ($last_bak) = @_; + my $t = time(); + my $delta = $t - $last_bak; + if ($delta > $opt_c) { + $state = $STATE_CRITICAL; + } elsif ($delta > $opt_w) { + $state = $STATE_WARNING; + } elsif ($delta >= 0) { + $state = $STATE_OK; + } + $delta = sprintf '%.2f', $delta/3600.0; + return ($state, $delta); +} + +sub print_status { + my ($host, $state, $message, $service) = @_; + my $state_msg = $ERRORS{$state}; + if (!$service) { + $service = 'backups'; + } + $line = "$host\t$service\t$state\t$state_msg $message\n"; + if ($opt_s) { + $opt_v && print STDERR "sending results to nagios...\n"; + open(NSCA, "|/usr/sbin/send_nsca -H $opt_s") or die("cannot start send_nsca: $!\n"); + print NSCA $line; + close(NSCA) or warn("could not close send_nsca pipe correctly: $!\n"); + } + if (!$opt_s || $opt_v) { + printf $line; + } +} + +sub check_flag { + my ($host, $flag) = @_; + my @stats = stat($flag); + if (not @stats) { + print_status($host, $STATE_UNKNOWN, "cannot stat flag $flag"); + } + else { + ($state, $delta) = check_age($stats[9]); + print_status($host, $state, "$delta hours old"); + } +} + +my $backupdir= $opt_d; + +my @hosts; +if (defined($opt_o)) { + @hosts=qx{hostname -f}; +} else { + # XXX: this should be a complete backup registry instead + @hosts=qx{ls $backupdir | grep -v lost+found}; +} + +chdir($backupdir); +my ($delta, $state, $host); +foreach $host (@hosts) { + chomp($host); + if ($opt_o) { + $dir = $backupdir; + } else { + $dir = $host; + } + my $flag; + if (-d $dir) { + # guess the backup type and find a proper stamp file to compare + @rdiffs = glob("$dir/*/rdiff-backup-data"); + foreach $subdir (@rdiffs) { + $subdir =~ s/rdiff-backup-data$//; + $opt_v && print STDERR "inspecting dir $subdir\n"; + check_rdiff($host, $subdir, $opt_v); + $flag = 1; + } + if (-d "$dir/dump") { + # XXX: this doesn't check backup consistency + $flag="$dir/dump/" . `ls -tr $dir/dump | tail -1`; + chomp($flag); + check_flag($host, $flag); + } elsif (-d "$dir/dup") { + # XXX: this doesn't check backup consistency + $flag="$dir/dup/" . `ls -tr $dir/dup | tail -1`; + chomp($flag); + check_flag($host, $flag); + } elsif (-r "$dir/rsync.log") { + # XXX: this doesn't check backup consistency + $flag="$dir/rsync.log"; + check_flag($host, $flag); + } + if (!$flag) { + print_status($host, $STATE_UNKNOWN, 'unknown system'); + } + } else { + print_status($host, $STATE_UNKNOWN, 'no directory'); + } +} diff --git a/files/nagios_plugins/duplicity/README.md b/files/nagios_plugins/duplicity/README.md new file mode 100644 index 00000000..1cd349af --- /dev/null +++ b/files/nagios_plugins/duplicity/README.md @@ -0,0 +1,24 @@ +duplicity-backup-status +======================= + +Backupninja generates duplicity configfiles, this nagios plugin can check their freshness. Currently only the config files generated by backupninja can be parsed and we depend on that. + +## Prerequisites + +Make sure you have python-argparse installed (yes an extra dependency, getopt doubles the amount of code, so I gave up on that). The Python script will look for the duplicity_freshness.sh shell script in /usr/local/lib/nagios/plugins/ or /usr/lib/nagios/plugins/ make sure you copy it there and make executable. + +## Getting started + +Run the python script from your nagios. Don't forget to specify some extras like when warnings or criticalities should be emerged. + +- -w WARNINC Number of hours allowed for incremential backup warning level default 28 +- -W WARNFULL Number of hours allowed for incremential backup critical level default 40 +- -c CRITINC Number of days allowed for full backup warning level default 52 +- -C CRITFULL Number of days allowed for full backup critical level default 60 + + +## TODO: + +- make it cuter, tidy up +- make it more robust +- support other config backends as backupninja - this can be done by writing more scripts like backupninja_duplicity_freshness.sh and parsing an extra parameter diff --git a/files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh b/files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh new file mode 100644 index 00000000..7af2bf7f --- /dev/null +++ b/files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh @@ -0,0 +1,268 @@ +#!/bin/bash +# -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*- +# vim: set filetype=sh sw=3 sts=3 expandtab autoindent: + +# Load backupninja library/helpers, because why reinventing the wheel? [Because my wheels weren't round] +# some duplication is to be expected +# this is only supposed to work with duplicity + +## Functions +# simple lowercase function +function tolower() { + echo "$1" | tr '[:upper:]' '[:lower:]' +} + +# we grab the current time once, since processing +# all the configs might take more than an hour. +nowtime=`LC_ALL=C date +%H` +nowday=`LC_ALL=C date +%d` +nowdayofweek=`LC_ALL=C date +%A` +nowdayofweek=`tolower "$nowdayofweek"` + +conffile="/etc/backupninja.conf" + +# find $libdirectory +libdirectory=`grep '^libdirectory' $conffile | /usr/bin/awk '{print $3}'` +if [ -z "$libdirectory" ]; then + if [ -d "/usr/lib/backupninja" ]; then + libdirectory="/usr/lib/backupninja" + else + echo "Could not find entry 'libdirectory' in $conffile." + fatal "Could not find entry 'libdirectory' in $conffile." + fi +else + if [ ! -d "$libdirectory" ]; then + echo "Lib directory $libdirectory not found." + fatal "Lib directory $libdirectory not found." + fi +fi + +. $libdirectory/tools + +setfile $conffile + +# get global config options (second param is the default) +getconf configdirectory /etc/backup.d +getconf scriptdirectory /usr/share/backupninja +getconf reportdirectory +getconf reportemail +getconf reporthost +getconf reportspace +getconf reportsuccess yes +getconf reportinfo no +getconf reportuser +getconf reportwarning yes +getconf loglevel 3 +getconf when "Everyday at 01:00" +defaultwhen=$when +getconf logfile /var/log/backupninja.log +getconf usecolors "yes" +getconf SLAPCAT /usr/sbin/slapcat +getconf LDAPSEARCH /usr/bin/ldapsearch +getconf RDIFFBACKUP /usr/bin/rdiff-backup +getconf CSTREAM /usr/bin/cstream +getconf MYSQLADMIN /usr/bin/mysqladmin +getconf MYSQL /usr/bin/mysql +getconf MYSQLHOTCOPY /usr/bin/mysqlhotcopy +getconf MYSQLDUMP /usr/bin/mysqldump +getconf PGSQLDUMP /usr/bin/pg_dump +getconf PGSQLDUMPALL /usr/bin/pg_dumpall +getconf PGSQLUSER postgres +getconf GZIP /bin/gzip +getconf GZIP_OPTS --rsyncable +getconf RSYNC /usr/bin/rsync +getconf admingroup root + +if [ ! -d "$configdirectory" ]; then + echo "Configuration directory '$configdirectory' not found." + fatal "Configuration directory '$configdirectory' not found." +fi + +# get the duplicity configuration +function get_dupconf(){ + setfile $1 + getconf options + getconf testconnect yes + getconf nicelevel 0 + getconf tmpdir + + setsection gpg + getconf password + getconf sign no + getconf encryptkey + getconf signkey + + setsection source + getconf include + getconf vsnames all + getconf vsinclude + getconf exclude + + setsection dest + getconf incremental yes + getconf increments 30 + getconf keep 60 + getconf keepincroffulls all + getconf desturl + getconf awsaccesskeyid + getconf awssecretaccesskey + getconf cfusername + getconf cfapikey + getconf cfauthurl + getconf ftp_password + getconf sshoptions + getconf bandwidthlimit 0 + getconf desthost + getconf destdir + getconf destuser + destdir=${destdir%/} +} + +### some voodoo to mangle the correct commands + +function mangle_cli(){ + + execstr_options="$options " + execstr_source= + if [ -n "$desturl" ]; then + [ -z "$destuser" ] || warning 'the configured destuser is ignored since desturl is set' + [ -z "$desthost" ] || warning 'the configured desthost is ignored since desturl is set' + [ -z "$destdir" ] || warning 'the configured destdir is ignored since desturl is set' + execstr_serverpart="$desturl" + else + execstr_serverpart="scp://$destuser@$desthost/$destdir" + fi + + + ### Symmetric or asymmetric (public/private key pair) encryption + if [ -n "$encryptkey" ]; then + execstr_options="${execstr_options} --encrypt-key $encryptkey" + fi + + ### Data signing (or not) + if [ "$sign" == yes ]; then + # duplicity is not able to sign data when using symmetric encryption + [ -n "$encryptkey" ] || fatal "The encryptkey option must be set when signing." + # if needed, initialize signkey to a value that is not empty (checked above) + [ -n "$signkey" ] || signkey="$encryptkey" + execstr_options="${execstr_options} --sign-key $signkey" + fi + + ### Temporary directory + precmd= + if [ -n "$tmpdir" ]; then + if [ ! -d "$tmpdir" ]; then + #info "Temporary directory ($tmpdir) does not exist, creating it." + mkdir -p "$tmpdir" + [ $? -eq 0 ] || fatal "Could not create temporary directory ($tmpdir)." + chmod 0700 "$tmpdir" + fi + #info "Using $tmpdir as TMPDIR" + precmd="${precmd}TMPDIR=$tmpdir " + fi + + ### Source + + set -o noglob + + # excludes + SAVEIFS=$IFS + IFS=$(echo -en "\n\b") + for i in $exclude; do + str="${i//__star__/*}" + execstr_source="${execstr_source} --exclude '$str'" + done + IFS=$SAVEIFS + + # includes + SAVEIFS=$IFS + IFS=$(echo -en "\n\b") + for i in $include; do + [ "$i" != "/" ] || fatal "Sorry, you cannot use 'include = /'" + str="${i//__star__/*}" + execstr_source="${execstr_source} --include '$str'" + done + IFS=$SAVEIFS + + set +o noglob + + execstr_options="${execstr_options} --ssh-options '$sshoptions'" + if [ "$bandwidthlimit" != 0 ]; then + [ -z "$desturl" ] || warning 'The bandwidthlimit option is not used when desturl is set.' + execstr_precmd="trickle -s -d $bandwidthlimit -u $bandwidthlimit" + fi +} + +#function findlastdates(){ +# outputfile=$1 +# lastfull=0 +# lastinc=0 +# backuptime=0 +# +# while read line; do +# atime=0 +# arr=() +# sort='' +# test=$(echo $line|awk '{if (NF == 7); if ($1 == "Full" || $1 == "Incremental") {print $4, $3, $6, $5}}' ) +# +# if [ -n "$test" ]; then +# backuptime=$(date -u -d "$test" +%s) +# +# arr=($(echo $line|awk '{print $1, $2, $3, $4, $5, $6}')) +# if [ ${arr[0]} == "Incremental" ] && [ "$lastinc" -lt "$backuptime" ] ; then +# lastinc=$backuptime +# elif [ ${arr[0]} == "Full" ] && [ "$lastfull" -lt "$backuptime" ] ; then +# lastfull=$backuptime +# fi +# +# fi +# +# done < $outputfile +# # a full backup can be seen as incremental too +# lastinc=$(echo $lastinc | awk 'max=="" || $1 > max {max=$1} END{ print max}') +#} + +function check_status() { + grep -q 'No orphaned or incomplete backup sets found.' $1 + if [ $? -ne 0 ] ; then + exit 2 + fi +} + +## +## this function handles the freshness check of a backup action +## + +function process_action() { + local file="$1" + local suffix="$2" + setfile $file + get_dupconf $1 + mangle_cli + + outputfile=`maketemp backupout` + export PASSPHRASE=$password + export FTP_PASSWORD=$ftp_password + output=` su -c \ + "$execstr_precmd duplicity $execstr_options collection-status $execstr_serverpart >$outputfile 2>&1"` + exit_code=$? + echo -n $outputfile + + #check_status + #findlastdates +} + +files=`find $configdirectory -follow -mindepth 1 -maxdepth 1 -type f ! -name '.*.swp' | sort -n` + +for file in $files; do + [ -f "$file" ] || continue + suffix="${file##*.}" + base=`basename $file` + if [ "${base:0:1}" == "0" -o "$suffix" == "disabled" ]; then + continue + fi + if [ -e "$scriptdirectory/$suffix" -a "$suffix" == "dup" ]; then + process_action $file $suffix + fi +done + diff --git a/files/nagios_plugins/duplicity/check_backupninja_duplicity.py b/files/nagios_plugins/duplicity/check_backupninja_duplicity.py new file mode 100644 index 00000000..8ed9ce68 --- /dev/null +++ b/files/nagios_plugins/duplicity/check_backupninja_duplicity.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python + +# Inspired by Arne Schwabe [with BSD license] +# Inspired by backupninja [that's gpl some version] +# minor changes by someon who doesn't understand all the license quirks + +from subprocess import Popen,PIPE +import sys +import time +import os +import argparse +import getopt + +def main(): + # getopt = much more writing + parser = argparse.ArgumentParser(description='Nagios Duplicity status checker') + + parser.add_argument("-w", dest="warninc", default=28, type=int, + help="Number of hours allowed for incremential backup warning level, default 28") + parser.add_argument("-W", dest="warnfull", default=31, type=int, + help="Number of days allowed for full backup warning level, default 31") + parser.add_argument("-c", dest="critinc", default=52, type=int, + help="Number of hours allowed for incremential backup critical level, default 52") + parser.add_argument("-C", dest="critfull", default=33, type=int, + help="Number of days allowed for full backup critical level, default 33") + args = parser.parse_args() + + okay = 0 + + # *sigh* check_output is from python 2.7 and onwards. Debian, upgrade yourself. + #output , err = check_output(['/root/freshness.sh']) + + if os.path.isfile("/usr/lib/nagios/plugins/backupninja_duplicity_freshness.sh") and os.access("/usr/lib/nagios/plugins/backupninja_duplicity_freshness.sh", os.X_OK): + checkstatus, err = Popen(['/bin/bash', '/usr/lib/nagios/plugins/backupninja_duplicity_freshness.sh'], stdout=PIPE, stderr=PIPE, env={'HOME': '/root', 'PATH': os.environ['PATH']}).communicate() + elif os.path.isfile("/usr/local/lib/nagios/plugins/backupninja_duplicity_freshness.sh") and os.access("/usr/local/lib/nagios/plugins/backupninja_duplicity_freshness.sh", os.X_OK): + checkstatus, err = Popen(['/bin/bash', '/usr/local/lib/nagios/plugins/backupninja_duplicity_freshness.sh'], stdout=PIPE, stderr=PIPE, env={'HOME': '/root', 'PATH': os.environ['PATH']}).communicate() + + # Don't use exec(), popen(), etc. to execute external commands without explicity using the full path of the external program. Hijacked search path could be problematic. + #checkstatus, err = Popen(['/bin/bash', './freshness.sh'], stdout=PIPE, stderr=PIPE, env={'HOME': '/root', 'PATH': os.environ['PATH']}).communicate() + + #another sigh: Debian testing, upgrade yourself, this is only needed because Debian testing uses duplicity 0.6.18-3 + # open file read/write + f = open (checkstatus,"r") + checklines = f.readlines() + f.close() + + # remove the line that says Import of duplicity.backends.giobackend Failed: No module named gio + f = open(checkstatus,"w") + for line in checklines: + if not 'Import of duplicity.backends.giobackend Failed: No module named gio' in line: + f.write(line) + f.close() + + output = open(checkstatus).read() + + lastfull, lastinc = findlastdates(output) + + sincelastfull = time.time() - lastfull + sincelastinc = time.time() - lastinc + + msg = "OK: " + + if sincelastfull > (args.warnfull * 24 * 3600) or sincelastinc > (args.warninc * 3600): + okay = 1 + msg = "WARNING: " + if sincelastfull > (args.critfull * 24 * 3600) or sincelastinc > (args.critinc * 3600): + okay = 2 + msg = "CRITICAL: " + if not checkoutput(output): + okay = max(okay,1) + msg = "WARNING: duplicity output: %s " % repr(output) + if err: + okay=2 + msg = "Unexpected output: %s, " % repr(err) + + print msg, "last full %s ago, last incremential %s ago|lastfull=%d, lastinc=%d" % ( formattime(sincelastfull), formattime(sincelastinc), sincelastfull, sincelastinc) + + #clean up cruft + os.remove(checkstatus) + sys.exit(okay) + +def checkoutput(output): + if not 'No orphaned or incomplete backup sets found.' in output: + return False + + return True + +def formattime(seconds): + days = seconds / (3600 * 24) + hours = seconds / 3600 % 24 + + if days: + return "%d days %d hours" % (days,hours) + else: + return "%d hours" % hours + + +def findlastdates(output): + lastfull = 0 + lastinc = 0 + + for line in output.split("\n"): + parts = line.split() + + # ['Incremental', 'Sun', 'Oct', '31', '03:00:04', '2010', '1'] + if len (parts) == 7 and parts[0] in ["Full","Incremental"]: + foo = time.strptime(" ".join(parts[1:6]),"%a %b %d %H:%M:%S %Y") + + backuptime = time.mktime(foo) + + if parts[0] == "Incremental" and lastinc < backuptime: + lastinc = backuptime + elif parts[0] == "Full" and lastfull < backuptime: + lastfull = backuptime + + + # Count a full backup as incremental backup + lastinc = max(lastfull,lastinc) + return (lastfull, lastinc) + + +if __name__=='__main__': + main() diff --git a/manifests/cron.pp b/manifests/cron.pp new file mode 100644 index 00000000..bd4e857c --- /dev/null +++ b/manifests/cron.pp @@ -0,0 +1,17 @@ +# Write the backupninja cron job, allowing you to specify an alternate backupninja +# command (if you want to wrap it in any other commands, e.g. to allow it to use +# the monkeysphere for authentication), or a different schedule to run it on. +define backupninja::cron( + $backupninja_cmd = '/usr/sbin/backupninja', + $backupninja_test_cmd = $backupninja_cmd, + $cronfile = "/etc/cron.d/backupninja", + $min = "0", $hour = "*", $dom = "*", $month = "*", + $dow = "*") +{ + file { $cronfile: + content => template('backupninja/backupninja.cron.erb'), + owner => root, + group => root, + mode => 0644 + } +} diff --git a/manifests/duplicity.pp b/manifests/duplicity.pp new file mode 100644 index 00000000..a05da876 --- /dev/null +++ b/manifests/duplicity.pp @@ -0,0 +1,147 @@ +# Run duplicity-backup as part of a backupninja run. +# +# Valid attributes for this type are: +# +# order: +# +# The prefix to give to the handler config filename, to set order in +# which the actions are executed during the backup run. +# +# ensure: +# +# Allows you to delete an entry if you don't want it any more (but be +# sure to keep the configdir, name, and order the same, so that we can +# find the correct file to remove). +# +# options, nicelevel, testconnect, tmpdir, sign, encryptkey, signkey, +# password, include, exclude, vsinclude, incremental, keep, bandwidthlimit, +# sshoptions, destdir, desthost, desuser: +# +# As defined in the backupninja documentation. The options will be +# placed in the correct sections automatically. The include and +# exclude options should be given as arrays if you want to specify +# multiple directories. +# +# directory, ssh_dir_manage, ssh_dir, authorized_keys_file, installuser, +# installkey, backuptag: +# +# Options for the bakupninja::server::sandbox define, check that +# definition for more info. +# +# Some notes about this handler: +# +# - When specifying a password, be sure to enclose it in single quotes, +# this is particularly important if you have any special characters, such +# as a $ which puppet will attempt to interpret resulting in a different +# password placed in the file than you expect! +# - There's no support for a 'local' type in backupninja's duplicity +# handler on version 0.9.6-4, which is the version available in stable and +# testing debian repositories by the time of this writing. +define backupninja::duplicity( $order = 90, + $ensure = present, + # options to the config file + $options = false, + $nicelevel = false, + $testconnect = false, + $tmpdir = false, + # [gpg] + $sign = false, + $encryptkey = false, + $signkey = false, + $password = false, + # [source] + $include = [ "/var/spool/cron/crontabs", + "/var/backups", + "/etc", + "/root", + "/home", + "/usr/local/*bin", + "/var/lib/dpkg/status*" ], + $exclude = [ "/home/*/.gnupg", + "/home/*/.local/share/Trash", + "/home/*/.Trash", + "/home/*/.thumbnails", + "/home/*/.beagle", + "/home/*/.aMule", + "/home/*/.gnupg", + "/home/*/.gpg", + "/home/*/.ssh", + "/home/*/gtk-gnutella-downloads", + "/etc/ssh/*" ], + $vsinclude = false, + # [dest] + $incremental = "yes", + $increments = false, + $keep = false, + $keepincroffulls = false, + $bandwidthlimit = false, + $sshoptions = false, + $destdir = false, + $desthost = false, + $destuser = false, + $desturl = false, + # configs to backupninja client + $backupkeystore = $backupninja::keystore, + $backupkeystorefspath = $backupninja::keystorefspath, + $backupkeytype = $backupninja::keytype, + $backupkeydest = $backupninja::keydest, + $backupkeydestname = $backupninja::keydestname, + # options to backupninja server sandbox + $ssh_dir_manage = true, + $ssh_dir = "${destdir}/.ssh", + $authorized_keys_file = 'authorized_keys', + $installuser = true, + $backuptag = "backupninja-${::fqdn}", + # key options + $createkey = false, + $keymanage = $backupninja::keymanage ) { + + # install client dependencies + ensure_resource('package', 'duplicity', {'ensure' => $backupninja::ensure_duplicity_version}) + + case $desthost { false: { err("need to define a destination host for remote backups!") } } + case $destdir { false: { err("need to define a destination directory for remote backups!") } } + case $password { false: { err("a password is necessary either to unlock the GPG key, or for symmetric encryption!") } } + + # guarantees there's a configured backup space for this backup + backupninja::server::sandbox { "${user}-${name}": + user => $destuser, + host => $desthost, + dir => $destdir, + manage_ssh_dir => $ssh_dir_manage, + ssh_dir => $ssh_dir, + authorized_keys_file => $authorized_keys_file, + installuser => $installuser, + backuptag => $backuptag, + backupkeys => $backupkeystore, + keytype => $backupkeytype, + } + + # the client's ssh key + backupninja::key { "${destuser}-${name}": + user => $destuser, + createkey => $createkey, + keymanage => $keymanage, + keytype => $backupkeytype, + keystore => $backupkeystore, + keystorefspath => $backupkeystorefspath, + keydest => $backupkeydest, + keydestname => $backupkeydestname + } + + # the backupninja rule for this duplicity backup + file { "${backupninja::configdir}/${order}_${name}.dup": + ensure => $ensure, + content => template('backupninja/dup.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::configdir}"] + } + + if $backupninja::manage_nagios { + nagios::service::passive { $nagios_description: } + } + +} + diff --git a/manifests/generate_sshkey.pp b/manifests/generate_sshkey.pp new file mode 100644 index 00000000..a3008e50 --- /dev/null +++ b/manifests/generate_sshkey.pp @@ -0,0 +1,33 @@ +define backupninja::generate_sshkey( + $ssh_key_basepath = '/etc/puppet/modules/keys/files/backupkeys', +){ + + # generate backupninja ssh keypair + $ssh_key_name = "backup_${::hostname}_id_rsa" + $ssh_keys = ssh_keygen("${ssh_key_basepath}/${ssh_key_name}") + $public = split($ssh_keys[1],' ') + $public_type = $public[0] + $public_key = $public[1] + + file { '/root/.ssh': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0600'; + } + + # install ssh keypair on client + file { "/root/.ssh/$ssh_key_name": + content => $ssh_keys[0], + owner => root, + group => 0, + mode => '0600'; + } + + file { "/root/.ssh/$ssh_key_name.pub": + content => $public_key, + owner => root, + group => 0, + mode => '0666'; + } +} diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 00000000..e453e703 --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,52 @@ +# configure backupninja +class backupninja ( + $ensure_backupninja_version = 'installed', + $ensure_rsync_version = 'installed', + $ensure_rdiffbackup_version = 'installed', + $ensure_debconfutils_version = 'installed', + $ensure_hwinfo_version = 'installed', + $ensure_duplicity_version = 'installed', + $configdir = '/etc/backup.d', + $keystore = "${::fileserver}/keys/backupkeys", + $keystorefspath = false, + $keytype = 'rsa', + $keydest = '/root/.ssh', + $keyowner = 0, + $keygroup = 0, + $keymanage = true, + $configfile = '/etc/backupninja.conf', + $loglvl = 4, + $when = 'everyday at 01:00', + $reportemail = 'root', + $reportsuccess = false, + $reportwarning = true, + $reporthost = undef, + $reportuser = undef, + $reportdirectory = undef, + $logfile = '/var/log/backupninja.log', + $scriptdir = '/usr/share/backupninja', + $libdir = '/usr/lib/backupninja', + $usecolors = true, + $vservers = false, + $manage_nagios = false, +) { + + # install client dependencies + ensure_resource('package', 'backupninja', {'ensure' => $ensure_backupninja_version}) + + # set up backupninja config directory + file { $configdir: + ensure => directory, + mode => '0750', + owner => 0, + group => 0; + } + + file { $configfile: + content => template('backupninja/backupninja.conf.erb'), + owner => root, + group => 0, + mode => '0644' + } + +} diff --git a/manifests/key.pp b/manifests/key.pp new file mode 100644 index 00000000..9d34cdbd --- /dev/null +++ b/manifests/key.pp @@ -0,0 +1,41 @@ +# generate and deploy backupninja sshkeys +define backupninja::key( + $user = $name, + $createkey = false, + $keymanage = $backupninja::keymanage, + $keyowner = $backupninja::keyowner, + $keygroup = $backupninja::keygroup, + $keystore= $backupninja::keystore, + $keystorefspath = $backupninja::keystorefspath, + $keytype = $backupninja::keytype, + $keydest = $backupninja::keydest, + $keydestname = "id_${backupninja::keytype}" ) +{ + + # generate the key + if $createkey == true { + if $keystorefspath == false { + err('need to define a destination directory for sshkey creation!') + } + $ssh_keys = ssh_keygen("${keystorefspath}/${keydestname}") + } + + # deploy/manage the key + if $keymanage == true { + $keydestfile = "${keydest}/${keydestname}" + ensure_resource('file', $keydest, { + 'ensure' => 'directory', + 'mode' => '0700', + 'owner' => $keyowner, + 'group' => $keygroup + }) + ensure_resource('file', $keydestfile, { + 'ensure' => 'present', + 'source' => "${keystore}/${user}_id_${keytype}", + 'mode' => '0700', + 'owner' => $keyowner, + 'group' => $keygroup, + 'require' => File[$keydest], + }) + } +} diff --git a/manifests/labelmount.pp b/manifests/labelmount.pp new file mode 100644 index 00000000..8974cec1 --- /dev/null +++ b/manifests/labelmount.pp @@ -0,0 +1,62 @@ +# Mount a labelled partition on a directory as part of a backupninja run. +# +# This type will automatically create an unmount action with an order of 99 +# for the destination directory you specify here. +# +# Valid attributes for this type are: +# +# order: The prefix to give to the handler config filename, to set +# order in which the actions are executed during the backup run. Note +# that the value given here should be less than any action which +# requires the filesystem to be mounted! +# +# ensure: Allows you to delete an entry if you don't want it any more +# (but be sure to keep the configdir, name, and order the same, so +# that we can find the correct file to remove). +# +# label: The partition label to mount. +# +# dest: The directory to mount the partition onto. +# +define backupninja::labelmount($order = 10, + $ensure = present, + $label, + $dest + ) { + file { "${backupninja::configdir}/${order}_${name}.labelmount": + ensure => $ensure, + content => template('backupninja/labelmount.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::configdir}"] + } + + file { "${backupninja::configdir}/99_${name}.umount": + ensure => $ensure, + content => template('backupninja/umount.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::configdir}"] + } + + # Copy over the handler scripts themselves, since they're not in the + # standard distribution, and are unlikely to end up there any time + # soon because backupninja's "build" system is balls. + file { "/usr/share/backupninja/labelmount": + content => template('backupninja/labelmount.handler'), + owner => root, + group => root, + mode => 0755, + require => Package[backupninja] + } + + file { "/usr/share/backupninja/umount": + content => template('backupninja/umount.handler'), + owner => root, + group => root, + mode => 0755, + require => Package[backupninja] + } +} diff --git a/manifests/maildir.pp b/manifests/maildir.pp new file mode 100644 index 00000000..2454b82d --- /dev/null +++ b/manifests/maildir.pp @@ -0,0 +1,43 @@ +# maildir handler, as part of a backupninja run. +# +# The maildir handler slowly creates a backup of each user's +# maildir to a remote server. It is designed to be run with +# low overhead in terms of CPU and bandwidth, so it runs pretty +# slow. Hardlinking is used to save storage space. The actual +# maildir is stored within each snapshot directory. +# +# Valid attributes for this type are: +# +# order: The prefix to give to the handler config filename, to set +# order in which the actions are executed during the backup run. +# +# ensure: Allows you to delete an entry if you don't want it any more +# (but be sure to keep the configdir, name, and order the same, so +# that we can find the correct file to remove). +# +# +define backupninja::maildir( + $order = 99, $ensure = present, + $when = 'everyday at 21:00', $srcdir = false, + $destdir = false, $desthost = false, $destuser = false, $destid_file = false, + $remove = false, $multiconnection = yes, $keepdaily='4', $keepweekly='2', + $keepmonthly='2') +{ + # install client dependencies + ensure_resource('package', 'rsync', {'ensure' => $backupninja::ensure_rsync_version}) + + case $srcdir { false: { err("need to define a source directory to backup!") } } + case $destdir { false: { err("need to define a destination directory to backup!") } } + case $desthost { false: { err("need to define a destination host for backups!") } } + case $destuser { false: { err("need to define a destination user for backups!") } } + case $destid_file { false: { err("need to define a ssh key id file to use!") } } + + file { "${backupninja::configdir}/${order}_${name}.maildir": + ensure => $ensure, + content => template('backupninja/maildir.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::configdir}"] + } +} diff --git a/manifests/mysql.pp b/manifests/mysql.pp new file mode 100644 index 00000000..b8877c05 --- /dev/null +++ b/manifests/mysql.pp @@ -0,0 +1,38 @@ +# Safe MySQL dumps, as part of a backupninja run. +# +# Valid attributes for this type are: +# +# order: The prefix to give to the handler config filename, to set +# order in which the actions are executed during the backup run. +# +# ensure: Allows you to delete an entry if you don't want it any more +# (but be sure to keep the configdir, name, and order the same, so +# that we can find the correct file to remove). +# +# user, dbusername, dbpassword, dbhost, databases, backupdir, +# hotcopy, sqldump, compress, configfile: As defined in the +# backupninja documentation, with the caveat that hotcopy, sqldump, +# and compress take true/false rather than yes/no. +# +define backupninja::mysql( + $order = 10, $ensure = present, $user = false, $dbusername = false, $dbpassword = false, + $dbhost = 'localhost', $databases = 'all', $backupdir = false, $hotcopy = false, + $sqldump = false, $compress = false, $configfile = true, + $vsname = false, $sqldumpoptions = '--lock-tables --complete-insert --add-drop-table --quick --quote-names', + $nodata = false) +{ + + $real_configfile = $configfile ? { + true => "/etc/mysql/debian.cnf", + default => $configfile, + } + + file { "${backupninja::configdir}/${order}_${name}.mysql": + ensure => $ensure, + content => template('backupninja/mysql.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::configdir}"] + } +} diff --git a/manifests/nagios_plugin/duplicity.pp b/manifests/nagios_plugin/duplicity.pp new file mode 100644 index 00000000..7dbd2633 --- /dev/null +++ b/manifests/nagios_plugin/duplicity.pp @@ -0,0 +1,45 @@ +class backupninja::nagios_plugin::duplicity { + case $::operatingsystem { + 'Debian': { package { 'python-argparse': ensure => installed, } } + 'Ubuntu': { package { 'python-argh': ensure => installed, } } + default: { + notify {'Backupninja-Duplicity Nagios check needs python-argparse to be installed !':} } + } + + file { '/usr/lib/nagios/plugins/check_backupninja_duplicity.py': + source => 'puppet:///modules/backupninja/nagios_plugins/duplicity/check_backupninja_duplicity.py', + mode => '0755', + owner => 'nagios', + group => 'nagios', + } + + # deploy helper script + file { '/usr/lib/nagios/plugins/backupninja_duplicity_freshness.sh': + source => 'puppet:///modules/backupninja/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh', + mode => '0755', + owner => 'nagios', + group => 'nagios', + } + + nagios::nrpe::command { 'check_backupninja_duplicity': + command_line => "sudo ${::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity.py" + } + sudo::spec {'nrpe_check_backupninja_duplicity': + ensure => present, + users => 'nagios', + hosts => 'ALL', + commands => "NOPASSWD: ${::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity.py"; + } + + nagios::service { "Backupninja Duplicity $::fqdn": + use_nrpe => true, + check_command => 'check_backupninja_duplicity', + nrpe_timeout => '60', + # check only twice a day + normal_check_interval => '720', + # recheck every hour + retry_check_interval => '60', + } + + +} diff --git a/manifests/pgsql.pp b/manifests/pgsql.pp new file mode 100644 index 00000000..d4814be9 --- /dev/null +++ b/manifests/pgsql.pp @@ -0,0 +1,27 @@ +# Safe PGSQL dumps, as part of a backupninja run. +# +# Valid attributes for this type are: +# +# order: The prefix to give to the handler config filename, to set +# order in which the actions are executed during the backup run. +# +# ensure: Allows you to delete an entry if you don't want it any more +# (but be sure to keep the configdir, name, and order the same, so +# that we can find the correct file to remove). +# +# backupdir, compress, configfile: As defined in the +# backupninja documentation, with the caveat that hotcopy, sqldump, +# and compress take true/false rather than yes/no. +# +define backupninja::pgsql( + $order = 10, $ensure = present, $databases = 'all', $backupdir = "/var/backups/postgres", $compress = true, $vsname = false) +{ + file { "${backupninja::configdir}/${order}_${name}.pgsql": + ensure => $ensure, + content => template('backupninja/pgsql.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::configdir}"] + } +} diff --git a/manifests/rdiff.pp b/manifests/rdiff.pp new file mode 100644 index 00000000..cd73d22c --- /dev/null +++ b/manifests/rdiff.pp @@ -0,0 +1,109 @@ +# Run rdiff-backup as part of a backupninja run. +# +# Valid attributes for this type are: +# +# order: The prefix to give to the handler config filename, to set +# order in which the actions are executed during the backup run. +# +# ensure: Allows you to delete an entry if you don't want it any more +# (but be sure to keep the configdir, name, and order the same, so +# that we can find the correct file to remove). +# +# keep, include, exclude, type, host, directory, user, sshoptions: As +# defined in the backupninja documentation. The options will be placed +# in the correct sections automatically. The include and exclude +# options should be given as arrays if you want to specify multiple +# directories. +# +define backupninja::rdiff( $order = 90, + $ensure = present, + # [general] + $options = '--force', + $extras = false, + # [source] + $include = [ "/var/spool/cron/crontabs", + "/var/backups", + "/etc", + "/root", + "/home", + "/usr/local/*bin", + "/var/lib/dpkg/status*" + ], + $exclude = [ "/home/*/.gnupg", + "/home/*/.local/share/Trash", + "/home/*/.Trash", + "/home/*/.thumbnails", + "/home/*/.beagle", + "/home/*/.aMule", + "/home/*/gtk-gnutella-downloads" + ], + $vsinclude = false, + # [dest] + $type = 'local', + $host = false, + $user = false, + $home = "/home/${user}-${name}", + $keep = 30, + $sshoptions = false, + # ssh keypair config + $key = false, + $keymanage = $backupninja::keymanage, + $backupkeystore = $backupninja::keystore, + $backupkeytype = $backupninja::keytype, + $ssh_dir_manage = true, + $ssh_dir = "${home}/.ssh", + $authorized_keys_file = 'authorized_keys', + # sandbox config + $installuser = true, + $backuptag = "backupninja-${::fqdn}", + # monitoring + $nagios_description = "backups-${name}" ) { + + # install client dependencies + ensure_resource('package', 'rdiff-backup', {'ensure' => $backupninja::ensure_rdiffbackup_version}) + + $directory = "$home/$name/" + + case $type { + 'remote': { + case $host { false: { err("need to define a host for remote backups!") } } + + backupninja::server::sandbox { "${user}-${name}": + user => $user, + host => $host, + dir => $home, + manage_ssh_dir => $ssh_dir_manage, + ssh_dir => $ssh_dir, + key => $key, + authorized_keys_file => $authorized_keys_file, + installuser => $installuser, + backuptag => $backuptag, + backupkeys => $backupkeystore, + keytype => $backupkeytype, + } + + backupninja::key { "${user}-${name}": + user => $user, + keymanage => $keymanage, + keytype => $backupkeytype, + keystore => $backupkeystore, + } + } + } + + + file { "${backupninja::configdir}/${order}_${name}.rdiff": + ensure => $ensure, + content => template('backupninja/rdiff.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::configdir}"] + } + + if $backupninja::manage_nagios { + nagios::service::passive { $nagios_description: } + } + +} + diff --git a/manifests/rsync.pp b/manifests/rsync.pp new file mode 100644 index 00000000..fc59950b --- /dev/null +++ b/manifests/rsync.pp @@ -0,0 +1,128 @@ +# Run rsync as part of a backupninja run. +# Based on backupninja::rdiff + +define backupninja::rsync( $order = 90, + $ensure = present, + # [general] + $log = false, + $partition = false, + $fscheck = false, + $read_only = false, + $mountpoint = false, + $format = false, + $days = false, + $keepdaily = false, + $keepweekly = false, + $keepmonthly = false, + $lockfile = false, + $nicelevel = 0, + $tmp = false, + $multiconnection = false, + $enable_mv_timestamp_bug = false, + # [source] + $include = [ "/var/spool/cron/crontabs", + "/var/backups", + "/etc", + "/root", + "/home", + "/usr/local/*bin", + "/var/lib/dpkg/status*" + ], + $exclude = [ "/home/*/.gnupg", + "/home/*/.local/share/Trash", + "/home/*/.Trash", + "/home/*/.thumbnails", + "/home/*/.beagle", + "/home/*/.aMule", + "/home/*/gtk-gnutella-downloads" + ], + # [dest] + $host = false, + $user = false, + $home = "/home/${user}-${name}", + $subfolder = 'rsync', + $testconnect = false, + $ssh = false, + $protocol = false, + $numericids = false, + $compress = false, + $port = false, + $bandwidthlimit = false, + $remote_rsync = false, + $batch = false, + $batchbase = false, + $fakesuper = false, + $id_file = false, + # [services] + $initscripts = false, + $service = false, + # [system] + $rm = false, + $cp = false, + $touch = false, + $mv = false, + $fsck = false, + # ssh keypair config + $key = false, + $keymanage = $backupninja::keymanage, + $backupkeystore = $backupninja::keystore, + $backupkeytype = $backupninja::keytype, + $ssh_dir_manage = true, + $ssh_dir = "${home}/.ssh", + $authorized_keys_file = 'authorized_keys', + # sandbox config + $installuser = true, + $backuptag = "backupninja-${::fqdn}", + # monitoring + $nagios_description = "backups-${name}" ) { + + # install client dependencies + ensure_resource('package', 'rsync', {'ensure' => $backupninja::ensure_rsync_version}) + + # Right now just local origin with remote destination is supported. + $from = 'local' + $dest = 'remote' + + case $dest { + 'remote': { + case $host { false: { err("need to define a host for remote backups!") } } + + $directory = "${home}/${subfolder}/" + + backupninja::server::sandbox { "${user}-${name}": + user => $user, + host => $host, + dir => $home, + manage_ssh_dir => $ssh_dir_manage, + ssh_dir => $ssh_dir, + key => $key, + authorized_keys_file => $authorized_keys_file, + installuser => $installuser, + backuptag => $backuptag, + keytype => $backupkeytype, + backupkeys => $backupkeystore, + } + + backupninja::key { "${user}-${name}": + user => $user, + keymanage => $keymanage, + keytype => $backupkeytype, + keystore => $backupkeystore, + } + } + } + + file { "${backupninja::configdir}/${order}_${name}.rsync": + ensure => $ensure, + content => template('backupninja/rsync.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::configdir}"] + } + + if $backupninja::manage_nagios { + nagios::service::passive { $nagios_description: } + } + +} diff --git a/manifests/server.pp b/manifests/server.pp new file mode 100644 index 00000000..49e42a0f --- /dev/null +++ b/manifests/server.pp @@ -0,0 +1,147 @@ +# this define realizes all needed resources for a hosted backup +define backupninja_server_realize($host) { + User <<| tag == "backupninja-$host" |>> + File <<| tag == "backupninja-$host" |>> + Ssh_authorized_key <<| tag == "backupninja-$host" |>> +} + +class backupninja::server ( + $backupdir = '/backup', + $backupdir_ensure = 'directory', + $manage_nagios = false, + $nagios_server = undef, + $nagios_warn_level = 129600, + $nagios_crit_level = 216000, +) { + + group { "backupninjas": + ensure => "present", + gid => 700 + } + + file { $backupdir: + ensure => $backupdir_ensure, + mode => 0710, owner => root, group => "backupninjas", + require => $backupdir_ensure ? { + 'directory' => undef, + default => File["$backupdir_ensure"], + } + } + + if $manage_nagios { + + case $nagios_server { undef: { err('Cannot manage nagios without nagios_server parameter!') } } + + include nagios::nsca::client + + file { "/usr/local/bin/checkbackups": + ensure => "present", + source => "puppet:///modules/backupninja/checkbackups.pl", + mode => 0755, owner => root, group => root, + } + + cron { checkbackups: + command => "/usr/local/bin/checkbackups -d ${backupdir} -s ${nagios_server} -w ${nagios_warn_level} -c ${nagios_crit_level} | grep -v 'sent to host successfully'", + user => "root", + hour => "8-23", + minute => 59, + require => [ File["/usr/local/bin/checkbackups"], Package['nsca'] ] + } + } + + # collect all resources from hosted backups + Backupninja_server_realize <<| tag == $::fqdn |>> + + # this define allows nodes to declare a remote backup sandbox, that have to + # get created on the server + define sandbox ( + $user = $name, + $host = $::fqdn, + $installuser = true, + $dir, + $manage_ssh_dir = true, + $ssh_dir = "${dir}/.ssh", + $authorized_keys_file = 'authorized_keys', + $key = false, + $keytype = 'dss', + $backupkeys = "${fileserver}/keys/backupkeys", + $uid = false, + $gid = "backupninjas", + $backuptag = "backupninja-${::fqdn}", + ) { + + if !defined(Backupninja_server_realize["${::fqdn}@${host}"]) { + @@backupninja_server_realize { "${::fqdn}@${host}": + host => $::fqdn, + tag => $host, + } + } + + if !defined(File["$dir"]) { + @@file { "$dir": + ensure => directory, + mode => 0750, owner => $user, group => 0, + tag => "$backuptag", + } + } + + if $installuser { + + if $manage_ssh_dir { + if !defined(File["$ssh_dir"]) { + @@file { "${ssh_dir}": + ensure => directory, + mode => 0700, owner => $user, group => 0, + require => [User[$user], File["$dir"]], + tag => "$backuptag", + } + } + } + + if $key { + # $key contais ssh public key + if !defined(Ssh_autorized_key["$user"]) { + @@ssh_authorized_key{ "$user": + type => $keytype, + key => $key, + user => $user, + target => "${ssh_dir}/${authorized_keys_file}", + tag => "$backuptag", + require => User[$user], + } + } + } + else { + # get ssh public key exists from server + if !defined(File["${ssh_dir}/${authorized_keys_file}"]) { + @@file { "${ssh_dir}/${authorized_keys_file}": + ensure => present, + mode => 0644, owner => 0, group => 0, + source => "${backupkeys}/${user}_id_${keytype}.pub", + require => File["${ssh_dir}"], + tag => "$backuptag", + } + } + } + + if !defined(User["$user"]) { + @@user { "$user": + ensure => "present", + uid => $uid ? { + false => undef, + default => $uid + }, + gid => "$gid", + comment => "$user backup sandbox", + home => "$dir", + managehome => true, + shell => "/bin/bash", + password => '*', + require => Group['backupninjas'], + tag => "$backuptag" + } + } + } + } +} + diff --git a/manifests/sh.pp b/manifests/sh.pp new file mode 100644 index 00000000..4a60e5fa --- /dev/null +++ b/manifests/sh.pp @@ -0,0 +1,25 @@ +# sh handler, as part of a backupninja run. +# +# Valid attributes for this type are: +# +# order: The prefix to give to the handler config filename, to set +# order in which the actions are executed during the backup run. +# +# ensure: Allows you to delete an entry if you don't want it any more +# (but be sure to keep the configdir, name, and order the same, so +# that we can find the correct file to remove). +# +# +define backupninja::sh($order = 50, + $ensure = present, + $command_string + ) { + file { "${backupninja::configdir}/${order}_${name}.sh": + ensure => $ensure, + content => template('backupninja/sh.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::configdir}"] + } +} diff --git a/manifests/svn.pp b/manifests/svn.pp new file mode 100644 index 00000000..1ab0597f --- /dev/null +++ b/manifests/svn.pp @@ -0,0 +1,28 @@ +# Subversion dumps, as part of a backupninja run. +# +# Valid attributes for this type are: +# +# order: The prefix to give to the handler config filename, to set +# order in which the actions are executed during the backup run. +# +# ensure: Allows you to delete an entry if you don't want it any more +# (but be sure to keep the configdir, name, and order the same, so +# that we can find the correct file to remove). +# +# +define backupninja::svn($order = 20, + $ensure = present, + $src = '/var/lib/svn', + $dest = '/var/backups/svn', + $tmp = '/var/backups/svn.tmp', + $vsname = false + ) { + file { "${backupninja::configdir}/${order}_${name}.svn": + ensure => $ensure, + content => template('backupninja/svn.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::configdir}"] + } +} diff --git a/manifests/sys.pp b/manifests/sys.pp new file mode 100644 index 00000000..946a525e --- /dev/null +++ b/manifests/sys.pp @@ -0,0 +1,45 @@ +# sys handler, as part of a backupninja run. +# +# Valid attributes for this type are: +# +# order: The prefix to give to the handler config filename, to set +# order in which the actions are executed during the backup run. +# +# ensure: Allows you to delete an entry if you don't want it any more +# (but be sure to keep the configdir, name, and order the same, so +# that we can find the correct file to remove). +# +# +define backupninja::sys($order = 30, + $ensure = present, + $parentdir = '/var/backups', + $packages = true, + $packagesfile = '/var/backups/dpkg-selections.txt', + $partitions = true, + $partitionsfile = '/var/backups/partitions.__star__.txt', + $dosfdisk = true, + $hardware = true, + $hardwarefile = '/var/backups/hardware.txt', + $dohwinfo = true, + $doluks = false, + $dolvm = false + ) { + + # install client dependencies + case $operatingsystem { + debian,ubuntu: { + ensure_resource('package', 'debconf-utils', {'ensure' => $backupninja::ensure_debconfutils_version}) + ensure_resource('package', 'hwinfo', {'ensure' => $backupninja::ensure_hwinfo_version}) + } + default: {} + } + + file { "${backupninja::configdir}/${order}_${name}.sys": + ensure => $ensure, + content => template('backupninja/sys.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::configdir}"] + } +} diff --git a/templates/backupninja.conf.erb b/templates/backupninja.conf.erb new file mode 100644 index 00000000..7706a615 --- /dev/null +++ b/templates/backupninja.conf.erb @@ -0,0 +1,25 @@ +# This configuration file was auto-generated by the Puppet configuration +# management system. Any changes you make to this file will be overwritten +# the next time Puppet runs. Please make configuration changes to this +# service in Puppet. + +loglevel = <%= @loglvl %> +when = <%= send(:when) %> +reportemail = <%= @reportemail %> +reportsuccess = <%= @reportsuccess ? 'yes' : 'no' %> +reportwarning = <%= @reportwarning ? 'yes' : 'no' %> +<% if reporthost.is_a? String -%> +<%= 'reporthost = ' + @reporthost %> +<% end -%> +<% if reportuser.is_a? String -%> +<%= 'reportuser = ' + @reportuser %> +<% end -%> +<% if reportdirectory.is_a? String -%> +<%= 'reportdirectory = ' + @reportdirectory %> +<% end -%> +logfile = <%= @logfile %> +configdirectory = <%= @configdir %> +scriptdirectory = <%= @scriptdir %> +libdirectory = <%= @libdir %> +usecolors = <%= @usecolors ? 'yes' : 'no' %> +vservers = <%= @vservers ? 'yes' : 'no' %> diff --git a/templates/backupninja.cron.erb b/templates/backupninja.cron.erb new file mode 100644 index 00000000..ec392ca9 --- /dev/null +++ b/templates/backupninja.cron.erb @@ -0,0 +1,6 @@ +# /etc/cron.d/backupninja -- cron tab entry for package backupninja + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +# # run backupninja +<%= min %> <%= hour %> <%= dom %> <%= month %> <%= dow %> root if [ -x <%= backupninja_test_cmd %> ]; then <%= backupninja_cmd %>; fi diff --git a/templates/dup.conf.erb b/templates/dup.conf.erb new file mode 100644 index 00000000..4f15e789 --- /dev/null +++ b/templates/dup.conf.erb @@ -0,0 +1,46 @@ +# This configuration file was auto-generated by the Puppet configuration +# management system. Any changes you make to this file will be overwritten +# the next time Puppet runs. Please make configuration changes to this +# service in Puppet. + +<%= 'options = ' + options if options %> +<%= 'nicelevel = ' + nicelevel if nicelevel %> +<%= 'testconnect = ' + testconnect if testconnect %> +<%= 'tmpdir = ' + tmpdir if tmpdir %> + +[gpg] +<%= 'sign = ' + sign if sign %> +<%= 'encryptkey = ' + encryptkey if encryptkey %> +<%= 'signkey = ' + signkey if signkey %> +<%= 'password = ' + password if password %> + +[source] +<% if include.is_a? String -%> +<%= 'include = ' + include %> +<% elsif include.is_a? Array -%> +<%= include.map { |i| "include = #{i}" }.join("\n") %> +<% end -%> + +<% if exclude.is_a? String -%> +<%= 'exclude = ' + exclude %> +<% elsif exclude.is_a? Array -%> +<%= exclude.map { |i| "exclude = #{i}" }.join("\n") %> +<% end -%> + +<% if vsinclude.is_a? String -%> +<%= 'vsinclude = ' + vsinclude %> +<% elsif vsinclude.is_a? Array -%> +<%= vsinclude.map { |i| "vsinclude = #{i}" }.join("\n") %> +<% end -%> + +[dest] +<%= 'incremental = ' + incremental if incremental %> +<%= 'increments = ' + increments if increments %> +<%= 'keep = ' + keep if keep %> +<%= 'keepincroffulls = ' + keepincroffulls if keepincroffulls %> +<%= 'bandwidthlimit = ' + bandwidthlimit if bandwidthlimit %> +<%= 'sshoptions = ' + sshoptions if sshoptions %> +<%= 'destdir = ' + destdir if destdir %> +<%= 'desthost = ' + desthost if desthost %> +<%= 'destuser = ' + destuser if destuser %> +<%= 'desturl = ' + desturl if desturl %> diff --git a/templates/labelmount.conf.erb b/templates/labelmount.conf.erb new file mode 100644 index 00000000..e40c49d3 --- /dev/null +++ b/templates/labelmount.conf.erb @@ -0,0 +1,2 @@ +label = <%= label %> +dest = <%= dest %> diff --git a/templates/labelmount.handler b/templates/labelmount.handler new file mode 100644 index 00000000..22090bd4 --- /dev/null +++ b/templates/labelmount.handler @@ -0,0 +1,17 @@ +#!/bin/sh + +# Mount a block device with the specified label ('label') onto the given +# directory ('dest'). + +getconf label +getconf dest + +if [ ! -b "/dev/disk/by-label/$label" ]; then + halt "No partition labelled '$label' is available" +fi + +if [ ! -d "$dest" ]; then + halt "Destination directory does not exist" +fi + +mount -t auto /dev/disk/by-label/$label $dest || halt "Mount failed" diff --git a/templates/maildir.conf.erb b/templates/maildir.conf.erb new file mode 100644 index 00000000..351f3824 --- /dev/null +++ b/templates/maildir.conf.erb @@ -0,0 +1,14 @@ +# This configuration file was auto-generated by the Puppet configuration +# management system. Any changes you make to this file will be overwritten +# the next time Puppet runs. Please make configuration changes to this +# service in Puppet. + +<% %w{when srcdir destdir desthost destuser destid_file keepdaily keepweekly keepmonthly}.each do |v| + if send(v) + -%><%= v + ' = ' + send(v) + "\n" %><% + end +end -%> + +remove = <%= remove ? 'yes' : 'no' %> +multiconnection = <%= multiconnection ? 'yes' : 'no' %> + diff --git a/templates/mysql.conf.erb b/templates/mysql.conf.erb new file mode 100644 index 00000000..b7ac5e8f --- /dev/null +++ b/templates/mysql.conf.erb @@ -0,0 +1,25 @@ +# This configuration file was auto-generated by the Puppet configuration +# management system. Any changes you make to this file will be overwritten +# the next time Puppet runs. Please make configuration changes to this +# service in Puppet. + +<% %w{user dbusername dbpassword dbhost databases backupdir vsname sqldumpoptions}.each do |v| + if send(v) + -%><%= v + ' = ' + send(v) + "\n" %><% + end +end -%> + +hotcopy = <%= hotcopy ? 'yes' : 'no' %> +sqldump = <%= sqldump ? 'yes' : 'no' %> +compress = <%= compress ? 'yes' : 'no' %> + +<% if real_configfile %> +configfile = <%= real_configfile %> +<% end %> + +<% if nodata.is_a? String -%> +<%= 'nodata = ' + nodata %> +<% elsif nodata.is_a? Array -%> +<%= "nodata = " + nodata.map { |i| "#{i}" }.join(" ") %> +<% end -%> + diff --git a/templates/pgsql.conf.erb b/templates/pgsql.conf.erb new file mode 100644 index 00000000..5ffa89c0 --- /dev/null +++ b/templates/pgsql.conf.erb @@ -0,0 +1,13 @@ +<% if vsname %> +vsname = <%= vsname %> +<% end %> +<% if backupdir %> +backupdir = <%= backupdir %> +<% end %> +<% if databases.is_a? String -%> +<%= 'databases = ' + databases %> +<% elsif databases.is_a? Array -%> +<%= "databases = " + databases.map { |i| "#{i}" }.join(" ") %> +<% end -%> +compress = <%= compress ? 'yes' : 'no' %> + diff --git a/templates/rdiff.conf.erb b/templates/rdiff.conf.erb new file mode 100644 index 00000000..23c336fc --- /dev/null +++ b/templates/rdiff.conf.erb @@ -0,0 +1,38 @@ +# This configuration file was auto-generated by the Puppet configuration +# management system. Any changes you make to this file will be overwritten +# the next time Puppet runs. Please make configuration changes to this +# service in Puppet. + +<%= 'options = ' + options if options %> + +<%= extras if extras %> + +[source] +type = local +<%= 'keep = ' + keep if keep %> + +<% if include.is_a? String -%> +<%= 'include = ' + include %> +<% elsif include.is_a? Array -%> +<%= include.map { |i| "include = #{i}" }.join("\n") %> +<% end -%> + +<% if exclude.is_a? String -%> +<%= 'exclude = ' + exclude %> +<% elsif exclude.is_a? Array -%> +<%= exclude.map { |i| "exclude = #{i}" }.join("\n") %> +<% end -%> + +<% if vsinclude.is_a? String -%> +<%= 'vsinclude = ' + vsinclude %> +<% elsif vsinclude.is_a? Array -%> +<%= vsinclude.map { |i| "vsinclude = #{i}" }.join("\n") %> +<% end -%> + +[dest] +<%- %w{type host directory user sshoptions}.each do |v| + if has_variable?(v) and instance_variable_get("@#{v}").to_s != "false" -%> +<%= v + ' = ' + instance_variable_get("@#{v}").to_s %> +<%- + end +end -%> diff --git a/templates/rsync.conf.erb b/templates/rsync.conf.erb new file mode 100644 index 00000000..778676fc --- /dev/null +++ b/templates/rsync.conf.erb @@ -0,0 +1,49 @@ +# This configuration file was auto-generated by the Puppet configuration +# management system. Any changes you make to this file will be overwritten +# the next time Puppet runs. Please make configuration changes to this +# service in Puppet. + +[general] +<%- %w{log partition fscheck read_only mountpoint backupdir format days keepdaily keepweekly keepmonthly lockfile nicelevel enable_mv_timestamp_bug, tmp, multiconnection}.each do |v| + if has_variable?(v) and instance_variable_get("@#{v}").to_s != "false" -%> +<%= v + ' = ' + instance_variable_get("@#{v}").to_s %> +<%- + end +end -%> + +[source] +<% unless from.empty? and from.to_s != "false" -%> +from = <%= from %> +<% end -%> +<%- %w{include exclude}.each do |v| + if has_variable?(v) + instance_variable_get("@#{v}").to_a.each do |parameter| -%> +<%= v + ' = ' + parameter %> +<%- + end + end +end -%> + +[dest] +<%- %w{dest testconnect ssh protocol numericids compress host port user id_file bandwidthlimit remote_rsync batch batchbase fakesuper}.each do |v| + if has_variable?(v) and instance_variable_get("@#{v}").to_s != "false" -%> +<%= v + ' = ' + instance_variable_get("@#{v}").to_s %> +<%- + end +end -%> + +[services] +<%- %w{initscripts service}.each do |v| + if has_variable?(v) and instance_variable_get("@#{v}").to_s != "false" -%> +<%= v + ' = ' + instance_variable_get("@#{v}").to_s %> +<%- + end +end -%> + +[system] +<%- %w{rm cp touch mv fsck}.each do |v| + if has_variable?(v) and instance_variable_get("@#{v}").to_s != "false" -%> +<%= v + ' = ' + instance_variable_get("@#{v}").to_s %> +<%- + end +end -%> diff --git a/templates/sh.conf.erb b/templates/sh.conf.erb new file mode 100644 index 00000000..f1b4161a --- /dev/null +++ b/templates/sh.conf.erb @@ -0,0 +1,10 @@ +#!/bin/sh +# +# This configuration file was auto-generated by the Puppet configuration +# management system. Any changes you make to this file will be overwritten +# the next time Puppet runs. Please make configuration changes to this +# service in Puppet. + +<% @command_string.each_line do |line| -%> +<%= line %> +<% end -%> diff --git a/templates/svn.conf.erb b/templates/svn.conf.erb new file mode 100644 index 00000000..465cc673 --- /dev/null +++ b/templates/svn.conf.erb @@ -0,0 +1,10 @@ +# This configuration file was auto-generated by the Puppet configuration +# management system. Any changes you make to this file will be overwritten +# the next time Puppet runs. Please make configuration changes to this +# service in Puppet. + +<% %w{src dest tmp vsname}.each do |v| + if send(v) + -%><%= v + ' = ' + send(v) + "\n" %><% + end +end -%> \ No newline at end of file diff --git a/templates/sys.conf.erb b/templates/sys.conf.erb new file mode 100644 index 00000000..a684e8b7 --- /dev/null +++ b/templates/sys.conf.erb @@ -0,0 +1,18 @@ +# This configuration file was auto-generated by the Puppet configuration +# management system. Any changes you make to this file will be overwritten +# the next time Puppet runs. Please make configuration changes to this +# service in Puppet. + +<% %w{parentdir packagesfile partitionsfile hardwarefile}.each do |v| + if send(v) + -%><%= v + ' = ' + send(v) + "\n" %><% + end +end -%> + +packages = <%= packages ? 'yes' : 'no' %> +partitions = <%= partitions ? 'yes' : 'no' %> +dosfdisk = <%= dosfdisk ? 'yes' : 'no' %> +hardware = <%= hardware ? 'yes' : 'no' %> +dohwinfo = <%= dohwinfo ? 'yes' : 'no' %> +luksheaders = <%= doluks ? 'yes' : 'no' %> +lvm = <%= dolvm ? 'yes' : 'no' %> diff --git a/templates/umount.conf.erb b/templates/umount.conf.erb new file mode 100644 index 00000000..59bfaec8 --- /dev/null +++ b/templates/umount.conf.erb @@ -0,0 +1 @@ +dir = <%= dest %> diff --git a/templates/umount.handler b/templates/umount.handler new file mode 100644 index 00000000..4fea195a --- /dev/null +++ b/templates/umount.handler @@ -0,0 +1,15 @@ +#!/bin/sh + +# Unmount the specified directory ('dir'), forcefully if necessary. + +getconf dir + +if ! umount $dir; then + warning "Simple unmount failed for $dir; being forceful" + if ! umount -f $dir; then + warning "Forceful unmount failed for $dir; being lazy" + if ! umount -l $dir; then + warning "Lazy unmount failed for $dir; you're on your own" + fi + fi +fi -- cgit v1.2.3