diff --git a/.gitignore b/.gitignore
index ed8b453a..85a8ccc7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,8 @@ docs/src/man1/*.1
docs/src/man7/*.7
docs/src/man7/cdist-type__*.rst
docs/src/cdist-reference.rst
+docs/src/cdist-types.rst
+docs/src/cdist.cfg.skeleton
# Ignore cdist cache for version control
/cache/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 44de6b0b..e215652c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,28 +1,20 @@
stages:
- test
+image: code.ungleich.ch:5050/ungleich-public/cdist/cdist-ci:latest
+
unit_tests:
stage: test
- before_script:
- - 'apk update'
- - 'apk add python3'
script:
- ./bin/build-helper version
- ./bin/build-helper test
pycodestyle:
stage: test
- before_script:
- - 'apk update'
- - 'apk add python3 py3-pycodestyle'
- - 'ln -f -s /usr/bin/pycodestyle-3 /usr/bin/pycodestyle'
script:
- ./bin/build-helper pycodestyle
shellcheck:
stage: test
- before_script:
- - 'wget https://storage.googleapis.com/shellcheck/shellcheck-stable.linux.x86_64.tar.xz'
- - 'tar xf shellcheck-stable.linux.x86_64.tar.xz && mv shellcheck-stable/shellcheck /usr/bin/'
script:
- ./bin/build-helper shellcheck
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..14682ad6
--- /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.
+
+ cdist
+ Copyright (C) 2019 ungleich-public
+
+ 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:
+
+ cdist Copyright (C) 2019 ungleich-public
+ 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/Makefile b/Makefile
index fa3327d1..f89ac1e7 100644
--- a/Makefile
+++ b/Makefile
@@ -63,6 +63,18 @@ DOCSREFSH=$(DOCS_SRC_DIR)/cdist-reference.rst.sh
$(DOCSREF): $(DOCSREFSH)
$(DOCSREFSH)
+# Html types list with references
+DOCSTYPESREF=$(MAN7DSTDIR)/cdist-types.rst
+DOCSTYPESREFSH=$(DOCS_SRC_DIR)/cdist-types.rst.sh
+
+$(DOCSTYPESREF): $(DOCSTYPESREFSH)
+ $(DOCSTYPESREFSH)
+
+DOCSCFGSKEL=./configuration/cdist.cfg.skeleton
+
+configskel: $(DOCSCFGSKEL)
+ cp -f "$(DOCSCFGSKEL)" "$(DOCS_SRC_DIR)/"
+
version:
@[ -f "cdist/version.py" ] || { \
printf "Missing 'cdist/version.py', please generate it first.\n" && exit 1; \
@@ -72,7 +84,7 @@ version:
man: version $(MANTYPES) $(DOCSREF)
$(SPHINXM)
-html: version $(MANTYPES) $(DOCSREF)
+html: version configskel $(MANTYPES) $(DOCSREF) $(DOCSTYPESREF)
$(SPHINXH)
docs: man html
@@ -114,6 +126,8 @@ speeches: $(SPEECHES)
#
clean: docs-clean
rm -f $(DOCS_SRC_DIR)/cdist-reference.rst
+ rm -f $(DOCS_SRC_DIR)/cdist-types.rst
+ rm -f $(DOCS_SRC_DIR)/cdist.cfg.skeleton
find "$(DOCS_SRC_DIR)" -mindepth 2 -type l \
| xargs rm -f
diff --git a/bin/build-helper b/bin/build-helper
index 7cfc4d55..ed41e438 100755
--- a/bin/build-helper
+++ b/bin/build-helper
@@ -74,6 +74,7 @@ SHELLCHECKCMD="shellcheck -s sh -f gcc -x"
# Skip SC2154 for variables starting with __ since such variables are cdist
# environment variables.
SHELLCHECK_SKIP=': __.*is referenced but not assigned.*\[SC2154\]'
+SHELLCHECKTMP=".shellcheck.tmp"
# Change to checkout directory
basedir="${0%/*}/../"
@@ -369,7 +370,7 @@ eof
cat << eof
Manual steps post release:
- cdist-web
- - send mail body generated in mailinglist.tmp and inform Dmitry for deb
+ - send generated mailinglist.tmp mail
- twitter
eof
;;
@@ -431,53 +432,67 @@ eof
;;
shellcheck-global-explorers)
- find cdist/conf/explorer -type f -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0
+ # shellcheck disable=SC2086
+ find cdist/conf/explorer -type f -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" > "${SHELLCHECKTMP}"
+ test ! -s "${SHELLCHECKTMP}" || { cat "${SHELLCHECKTMP}"; exit 1; }
;;
shellcheck-type-explorers)
- find cdist/conf/type -type f -path "*/explorer/*" -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0
+ # shellcheck disable=SC2086
+ find cdist/conf/type -type f -path "*/explorer/*" -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" > "${SHELLCHECKTMP}"
+ test ! -s "${SHELLCHECKTMP}" || { cat "${SHELLCHECKTMP}"; exit 1; }
;;
shellcheck-manifests)
- find cdist/conf/type -type f -name manifest -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0
+ # shellcheck disable=SC2086
+ find cdist/conf/type -type f -name manifest -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" > "${SHELLCHECKTMP}"
+ test ! -s "${SHELLCHECKTMP}" || { cat "${SHELLCHECKTMP}"; exit 1; }
;;
shellcheck-local-gencodes)
- find cdist/conf/type -type f -name gencode-local -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0
+ # shellcheck disable=SC2086
+ find cdist/conf/type -type f -name gencode-local -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" > "${SHELLCHECKTMP}"
+ test ! -s "${SHELLCHECKTMP}" || { cat "${SHELLCHECKTMP}"; exit 1; }
;;
shellcheck-remote-gencodes)
- find cdist/conf/type -type f -name gencode-remote -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0
+ # shellcheck disable=SC2086
+ find cdist/conf/type -type f -name gencode-remote -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" > "${SHELLCHECKTMP}"
+ test ! -s "${SHELLCHECKTMP}" || { cat "${SHELLCHECKTMP}"; exit 1; }
;;
shellcheck-scripts)
- ${SHELLCHECKCMD} scripts/cdist-dump scripts/cdist-new-type || exit 0
+ # shellcheck disable=SC2086
+ ${SHELLCHECKCMD} scripts/cdist-dump scripts/cdist-new-type > "${SHELLCHECKTMP}"
+ test ! -s "${SHELLCHECKTMP}" || { cat "${SHELLCHECKTMP}"; exit 1; }
;;
shellcheck-gencodes)
- "$0" shellcheck-local-gencodes
- "$0" shellcheck-remote-gencodes
+ "$0" shellcheck-local-gencodes || exit 1
+ "$0" shellcheck-remote-gencodes || exit 1
;;
shellcheck-types)
- "$0" shellcheck-type-explorers
- "$0" shellcheck-manifests
- "$0" shellcheck-gencodes
+ "$0" shellcheck-type-explorers || exit 1
+ "$0" shellcheck-manifests || exit 1
+ "$0" shellcheck-gencodes || exit 1
;;
shellcheck)
- "$0" shellcheck-global-explorers
- "$0" shellcheck-types
- "$0" shellcheck-scripts
+ "$0" shellcheck-global-explorers || exit 1
+ "$0" shellcheck-types || exit 1
+ "$0" shellcheck-scripts || exit 1
;;
shellcheck-type-files)
- find cdist/conf/type -type f -path "*/files/*" -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" || exit 0
+ # shellcheck disable=SC2086
+ find cdist/conf/type -type f -path "*/files/*" -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" > "${SHELLCHECKTMP}"
+ test ! -s "${SHELLCHECKTMP}" || { cat "${SHELLCHECKTMP}"; exit 1; }
;;
shellcheck-with-files)
- "$0" shellcheck
- "$0" shellcheck-type-files
+ "$0" shellcheck || exit 1
+ "$0" shellcheck-type-files || exit 1
;;
shellcheck-build-helper)
@@ -535,6 +550,7 @@ eof
# Temp files
rm -f ./*.tmp
+ rm -f ./.*.tmp
;;
distclean)
diff --git a/cdist/argparse.py b/cdist/argparse.py
index ca69cdae..611c484a 100644
--- a/cdist/argparse.py
+++ b/cdist/argparse.py
@@ -6,6 +6,7 @@ import collections
import functools
import cdist.configuration
import cdist.preos
+import cdist.info
# set of beta sub-commands
@@ -103,7 +104,7 @@ def get_parsers():
name="log level"),
help=('Set the specified verbosity level. '
'The levels, in order from the lowest to the highest, are: '
- 'ERROR (-1), WARNING (0), INFO (1), VERBOSE (2), DEBUG (3) '
+ 'ERROR (-1), WARNING (0), INFO (1), VERBOSE (2), DEBUG (3), '
'TRACE (4 or higher). If used along with -v then -v '
'increases last set value and -l overwrites last set '
'value.'),
@@ -424,7 +425,7 @@ def get_parsers():
parser['inventory'].set_defaults(
func=cdist.inventory.Inventory.commandline)
- # PreOs
+ # PreOS
parser['preos'] = parser['sub'].add_parser('preos', add_help=False)
# Shell
@@ -436,6 +437,37 @@ def get_parsers():
' should be POSIX compatible shell.'))
parser['shell'].set_defaults(func=cdist.shell.Shell.commandline)
+ # Info
+ parser['info'] = parser['sub'].add_parser('info')
+ parser['info'].add_argument(
+ '-a', '--all', help='Display all info. This is the default.',
+ action='store_true', default=False)
+ parser['info'].add_argument(
+ '-c', '--conf-dir',
+ help='Add configuration directory (can be repeated).',
+ action='append')
+ parser['info'].add_argument(
+ '-e', '--global-explorers',
+ help='Display info for global explorers.', action='store_true',
+ default=False)
+ parser['info'].add_argument(
+ '-F', '--fixed-string',
+ help='Interpret pattern as a fixed string.', action='store_true',
+ default=False)
+ parser['info'].add_argument(
+ '-f', '--full', help='Display full details.',
+ action='store_true', default=False)
+ parser['info'].add_argument(
+ '-g', '--config-file',
+ help='Use specified custom configuration file.',
+ dest="config_file", required=False)
+ parser['info'].add_argument(
+ '-t', '--types', help='Display info for types.',
+ action='store_true', default=False)
+ parser['info'].add_argument(
+ 'pattern', nargs='?', help='Glob pattern.')
+ parser['info'].set_defaults(func=cdist.info.Info.commandline)
+
for p in parser:
parser[p].epilog = EPILOG
diff --git a/cdist/conf/explorer/disks b/cdist/conf/explorer/disks
index 87a6b5c6..24540601 100755
--- a/cdist/conf/explorer/disks
+++ b/cdist/conf/explorer/disks
@@ -1,27 +1,67 @@
-#!/bin/sh
+#!/bin/sh -e
+#
+# based on previous work by other people, modified by:
+# 2020 Dennis Camera
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+# Finds disks of the system (excl. ram disks, floppy, cdrom)
uname_s="$(uname -s)"
-case "${uname_s}" in
+case $uname_s in
FreeBSD)
sysctl -n kern.disks
;;
- OpenBSD|NetBSD)
- sysctl -n hw.disknames | grep -Eo '[lsw]d[0-9]+' | xargs
+ OpenBSD)
+ sysctl -n hw.disknames | grep -Eo '[lsw]d[0-9]+'
+ ;;
+ NetBSD)
+ PATH="${PATH}:/usr/local/sbin:/usr/sbin:/sbin"
+ sysctl -n hw.disknames \
+ | awk 'BEGIN { RS = " " } /^[lsw]d[0-9]+/'
;;
Linux)
- if command -v lsblk > /dev/null
+ # list of major device numbers toexclude:
+ # ram disks, floppies, cdroms
+ # https://www.kernel.org/doc/Documentation/admin-guide/devices.txt
+ ign_majors='1 2 11'
+
+ if command -v lsblk >/dev/null 2>&1
then
- # exclude ram disks, floppies and cdroms
- # https://www.kernel.org/doc/Documentation/admin-guide/devices.txt
- lsblk -e 1,2,11 -dno name | xargs
+ lsblk -e "$(echo "$ign_majors" | tr ' ' ',')" -dno name
+ elif test -d /sys/block/
+ then
+ # shellcheck disable=SC2012
+ ls -1 /sys/block/ \
+ | awk -v ign_majors="$(echo "$ign_majors" | tr ' ' '|')" '
+ {
+ devfile = "/sys/block/" $0 "/dev"
+ getline devno < devfile
+ close(devfile)
+ if (devno !~ "^(" ign_majors "):") print
+ }'
else
- printf "Don't know how to list disks for %s operating system without lsblk, if you can please submit a patch\n" "${uname_s}" >&2
+ echo "Don't know how to list disks on Linux without lsblk and sysfs." >&2
+ echo 'If you can, please submit a patch.'>&2
fi
;;
*)
- printf "Don't know how to list disks for %s operating system, if you can please submit a patch\n" "${uname_s}" >&2
+ printf "Don't know how to list disks for %s operating system.\n" "${uname_s}" >&2
+ printf 'If you can please submit a patch\n' >&2
;;
-esac
-
-exit 0
+esac \
+| xargs
diff --git a/cdist/conf/explorer/init b/cdist/conf/explorer/init
index a8a7857e..f27c77ef 100755
--- a/cdist/conf/explorer/init
+++ b/cdist/conf/explorer/init
@@ -1,7 +1,8 @@
-#!/bin/sh
+#!/bin/sh -e
#
# 2016 Daniel Heule (hda at sfs.biz)
# Copyright 2017, Philippe Gregoire
+# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
@@ -19,21 +20,423 @@
# along with cdist. If not, see .
#
#
-# Returns the process name of pid 1 ( normaly the init system )
-# for example at linux this value is "init" or "systemd" in most cases
+# Returns the name of the init system (PID 1)
+
+# Expected values:
+# Linux:
+# Adélie Linux:
+# sysvinit+openrc
+# Alpine Linux:
+# busybox-init+openrc
+# ArchLinux:
+# systemd, sysvinit
+# CRUX:
+# sysvinit
+# Debian:
+# systemd, upstart, sysvinit, openrc, ???
+# Devuan:
+# sysvinit, sysvinit+openrc
+# Gentoo:
+# sysvinit+openrc, openrc-init, systemd
+# OpenBMC:
+# systemd
+# OpenWrt:
+# procd, init???
+# RedHat (RHEL, CentOS, Fedora, RedHat Linux, ...):
+# systemd, upstart, upstart-legacy, sysvinit
+# Slackware:
+# sysvinit
+# SuSE:
+# systemd, sysvinit
+# Ubuntu:
+# systemd, upstart, upstart-legacy, sysvinit
+# VoidLinux:
+# runit
#
+# GNU:
+# Debian:
+# sysvinit, hurd-init
+#
+# BSD:
+# {Free,Open,Net}BSD:
+# init
+#
+# Mac OS X:
+# launchd, init+SystemStarter
+#
+# Solaris/Illumos:
+# smf, init???
-uname_s="$(uname -s)"
+# NOTE: init systems can be stacked. This is popular to run OpenRC on top of
+# sysvinit (Gentoo) or busybox-init (Alpine), but can also be used to run runit
+# as a systemd service. This makes init system detection very complicated
+# (which result is expected?) This script tries to untangle some combinations,
+# OpenRC on top of sysv or busybox (X+openrc), but will ignore others (runit as
+# a systemd service)
-case "$uname_s" in
- Linux)
- (pgrep -P0 -l | awk '/^1[ \t]/ {print $2;}') || true
- ;;
- FreeBSD|OpenBSD)
- ps -o comm= -p 1 || true
- ;;
- *)
- # return a empty string as unknown value
- echo ""
- ;;
-esac
+# NOTE: When we have no idea, nothing will be printed!
+
+# NOTE:
+# When trying to gather information about the init system make sure to do so
+# without calling the binary! On some systems this triggers a reinitialisation
+# of the system which we don't want (e.g. embedded systems).
+
+
+set -e
+
+KERNEL_NAME=$(uname -s)
+
+KNOWN_INIT_SYSTEMS=$(cat </dev/null 2>&1 || return 1
+ launchctl getenv PATH >/dev/null || return 1
+ echo launchd
+}
+
+check_openrc() {
+ test -f /run/openrc/softlevel || return 1
+ echo openrc
+}
+
+check_procd() (
+ procd_path=${1:-/sbin/procd}
+ test -x "${procd_path}" || return 1
+ grep -q 'procd' "${procd_path}" || return 1
+ echo procd
+)
+
+check_runit() {
+ test -d /run/runit || return 1
+ echo runit
+}
+
+check_smf() {
+ # XXX: Is this the correct way??
+ test -f /etc/svc/volatile/svc_nonpersist.db || return 1
+ echo smf
+}
+
+check_systemd() {
+ # NOTE: sd_booted(3)
+ test -d /run/systemd/system/ || return 1
+ # systemctl --version | sed -e '/^systemd/!d;s/^systemd //'
+ echo systemd
+}
+
+check_systemstarter() {
+ test -d /System/Library/StartupItems/ || return 1
+ test -f /System/Library/StartupItems/LoginWindow/StartupParameters.plist || return 1
+ echo init+SystemStarter
+}
+
+check_sysvinit() (
+ init_path=${1:-/sbin/init}
+ test -x "${init_path}" || return 1
+ grep -q 'INIT_VERSION=sysvinit-[0-9.]*' "${init_path}" || return 1
+
+ # It is quite common to use SysVinit to stack other init systemd
+ # (like OpenRC) on top of it. So we check for that, too.
+ if stacked=$(check_openrc)
+ then
+ echo "sysvinit+${stacked}"
+ else
+ echo sysvinit
+ fi
+ unset stacked
+)
+
+check_upstart() {
+ test -x "$(command -v initctl)" || return 1
+ case $(initctl version)
+ in
+ *'(upstart '*')')
+ if test -d /etc/init
+ then
+ # modern (DBus-based?) upstart >= 0.5
+ echo upstart
+ elif test -d /etc/event.d
+ then
+ # ancient upstart
+ echo upstart-legacy
+ else
+ # whatever...
+ echo upstart
+ fi
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+}
+
+find_init_procfs() (
+ # First, check if the required file in procfs exists...
+ test -h /proc/1/exe || return 1
+
+ # Find init executable
+ init_exe=$(ls -l /proc/1/exe 2>/dev/null) || return 1
+ init_exe=${init_exe#* -> }
+
+ if ! test -x "$init_exe"
+ then
+ # On some rare occasions it can happen that the
+ # running init's binary has been replaced. In this
+ # case Linux adjusts the symlink to "X (deleted)"
+
+ # [root@fedora-12 ~]# readlink /proc/1/exe
+ # /sbin/init (deleted)
+ # [root@fedora-12 ~]# ls -l /proc/1/exe
+ # lrwxrwxrwx. 1 root root 0 2020-01-30 23:00 /proc/1/exe -> /sbin/init (deleted)
+
+ init_exe=${init_exe% (deleted)}
+ test -x "$init_exe" || return 1
+ fi
+
+ echo "${init_exe}"
+)
+
+guess_by_path() {
+ case $1
+ in
+ /bin/busybox)
+ check_busybox_init "$1" && return
+ ;;
+ /lib/systemd/systemd)
+ check_systemd "$1" && return
+ ;;
+ /hurd/init)
+ check_hurd_init "$1" && return
+ ;;
+ /sbin/launchd)
+ check_launchd "$1" && return
+ ;;
+ /usr/bin/runit|/sbin/runit)
+ check_runit "$1" && return
+ ;;
+ /sbin/openrc-init)
+ if check_openrc "$1" >/dev/null
+ then
+ echo openrc-init
+ return
+ fi
+ ;;
+ /sbin/procd)
+ check_procd "$1" && return
+ ;;
+ /sbin/init|*/init)
+ # init: it could be anything -> (explicit) no match
+ return 1
+ ;;
+ esac
+
+ # No match
+ return 1
+}
+
+guess_by_comm_name() {
+ case $1
+ in
+ busybox)
+ check_busybox_init && return
+ ;;
+ openrc-init)
+ if check_openrc >/dev/null
+ then
+ echo openrc-init
+ return 0
+ fi
+ ;;
+ init)
+ # init could be anything -> no match
+ return 1
+ ;;
+ *)
+ # Run check function by comm name if available.
+ # Fall back to comm name if either it does not exist or
+ # returns non-zero.
+ if type "check_$1" >/dev/null
+ then
+ "check_$1" && return
+ else
+ echo "$1" ; return 0
+ fi
+ esac
+
+ return 1
+}
+
+check_list() (
+ # List must be a multi-line input on stdin (one name per line)
+ while read -r init
+ do
+ "check_${init}" || continue
+ return 0
+ done
+ return 1
+)
+
+
+# BusyBox's versions of ps and pgrep do not support some options
+# depending on which compile-time options have been used.
+
+find_init_pgrep() {
+ pgrep -P0 -fl 2>/dev/null | awk -F '[[:blank:]]' '$1 == 1 { print $2 }'
+}
+
+find_init_ps() {
+ case $KERNEL_NAME
+ in
+ Darwin)
+ ps -o command -p 1 2>/dev/null | tail -n +2
+ ;;
+ FreeBSD)
+ ps -o args= -p 1 2>/dev/null | cut -d ' ' -f 1
+ ;;
+ Linux)
+ ps -o comm= -p 1 2>/dev/null
+ ;;
+ NetBSD)
+ ps -o comm= -p 1 2>/dev/null
+ ;;
+ OpenBSD)
+ ps -o args -p 1 2>/dev/null | tail -n +2 | cut -d ' ' -f 1
+ ;;
+ *)
+ ps -o args= -p 1 2>/dev/null
+ ;;
+ esac | trim # trim trailing whitespace (some ps like Darwin add it)
+}
+
+find_init() {
+ case $KERNEL_NAME
+ in
+ Linux|GNU|NetBSD)
+ find_init_procfs || find_init_pgrep || find_init_ps
+ ;;
+ FreeBSD)
+ find_init_procfs || find_init_ps
+ ;;
+ OpenBSD)
+ find_init_pgrep || find_init_ps
+ ;;
+ Darwin|SunOS)
+ find_init_ps
+ ;;
+ *)
+ echo "Don't know how to determine init." >&2
+ echo 'Please send a patch.' >&2
+ exit 1
+ esac
+}
+
+# -----
+
+init=$(find_init)
+
+# If we got a path, guess by the path first (fall back to file name if no match)
+# else guess by file name directly.
+# shellcheck disable=SC2015
+{
+ test -x "${init}" \
+ && guess_by_path "${init}" \
+ || guess_by_comm_name "$(basename "${init}")"
+} && exit 0 || true
+
+
+# Guessing based on the file path and name didn’t lead to a definitive result.
+#
+# We go through all of the checks until we find a match. To speed up the
+# process, common cases will be checked first based on the underlying kernel.
+
+{ common_candidates_by_kernel; echo "${KNOWN_INIT_SYSTEMS}"; } \
+ | unique | check_list
diff --git a/cdist/conf/explorer/os_release b/cdist/conf/explorer/os_release
index cfc01004..6489446b 100644
--- a/cdist/conf/explorer/os_release
+++ b/cdist/conf/explorer/os_release
@@ -1,6 +1,7 @@
#!/bin/sh
#
# 2018 Adam Dej (dejko.a at gmail.com)
+# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
@@ -21,6 +22,17 @@
# See os-release(5) and http://0pointer.de/blog/projects/os-release
-set +e
+if test -f /etc/os-release
+then
+ # Linux and FreeBSD (usually a symlink)
+ cat /etc/os-release
+elif test -f /usr/lib/os-release
+then
+ # systemd
+ cat /usr/lib/os-release
+elif test -f /var/run/os-release
+then
+ # FreeBSD (created by os-release service)
+ cat /var/run/os-release
+fi
-cat /etc/os-release || cat /usr/lib/os-release || true
diff --git a/cdist/conf/explorer/os_version b/cdist/conf/explorer/os_version
index 4c41695b..1d54ea60 100755
--- a/cdist/conf/explorer/os_version
+++ b/cdist/conf/explorer/os_version
@@ -70,4 +70,7 @@ case "$("$__explorer/os")" in
ubuntu)
lsb_release -sr
;;
-esac
+ alpine)
+ cat /etc/alpine-release
+ ;;
+esac
\ No newline at end of file
diff --git a/cdist/conf/type/__acl/gencode-remote b/cdist/conf/type/__acl/gencode-remote
index 6dab4d09..e5404a9d 100755
--- a/cdist/conf/type/__acl/gencode-remote
+++ b/cdist/conf/type/__acl/gencode-remote
@@ -20,7 +20,13 @@
file_is="$( cat "$__object/explorer/file_is" )"
-[ "$file_is" = 'missing' ] && [ -z "$__cdist_dry_run" ] && exit 0
+if [ "$file_is" = 'missing' ] \
+ && [ -z "$__cdist_dry_run" ] \
+ && \( [ ! -f "$__object/parameter/file" ] \
+ || [ ! -f "$__object/parameter/directory" ] \)
+then
+ exit 0
+fi
os="$( cat "$__global/explorer/os" )"
@@ -28,7 +34,20 @@ acl_path="/$__object_id"
acl_is="$( cat "$__object/explorer/acl_is" )"
-if [ -f "$__object/parameter/acl" ]
+if [ -f "$__object/parameter/source" ]
+then
+ acl_source="$( cat "$__object/parameter/source" )"
+
+ if [ "$acl_source" = '-' ]
+ then
+ acl_should="$( cat "$__object/stdin" )"
+ else
+ acl_should="$( grep -Ev '^#|^$' "$acl_source" )"
+ fi
+elif [ -f "$__object/parameter/entry" ]
+then
+ acl_should="$( cat "$__object/parameter/entry" )"
+elif [ -f "$__object/parameter/acl" ]
then
acl_should="$( cat "$__object/parameter/acl" )"
elif
diff --git a/cdist/conf/type/__acl/man.rst b/cdist/conf/type/__acl/man.rst
index 85e946ce..28412871 100644
--- a/cdist/conf/type/__acl/man.rst
+++ b/cdist/conf/type/__acl/man.rst
@@ -15,10 +15,24 @@ See ``setfacl`` and ``acl`` manpages for more details.
REQUIRED MULTIPLE PARAMETERS
----------------------------
-acl
+entry
Set ACL entry following ``getfacl`` output syntax.
+OPTIONAL PARAMETERS
+-------------------
+source
+ Read ACL entries from stdin or file.
+ Ordering of entries is not important.
+ When reading from file, comments and empty lines are ignored.
+
+file
+ Create/change file with ``__file`` using ``user:group:mode`` pattern.
+
+directory
+ Create/change directory with ``__directory`` using ``user:group:mode`` pattern.
+
+
BOOLEAN PARAMETERS
------------------
default
@@ -36,8 +50,8 @@ remove
DEPRECATED PARAMETERS
---------------------
-Parameters ``user``, ``group``, ``mask`` and ``other`` are deprecated and they
-will be removed in future versions. Please use ``acl`` parameter instead.
+Parameters ``acl``, ``user``, ``group``, ``mask`` and ``other`` are deprecated and they
+will be removed in future versions. Please use ``entry`` parameter instead.
EXAMPLES
@@ -49,27 +63,38 @@ EXAMPLES
--default \
--recursive \
--remove \
- --acl user:alice:rwx \
- --acl user:bob:r-x \
- --acl group:project-group:rwx \
- --acl group:some-other-group:r-x \
- --acl mask::r-x \
- --acl other::r-x
+ --entry user:alice:rwx \
+ --entry user:bob:r-x \
+ --entry group:project-group:rwx \
+ --entry group:some-other-group:r-x \
+ --entry mask::r-x \
+ --entry other::r-x
# give Alice read-only access to subdir,
# but don't allow her to see parent content.
__acl /srv/project2 \
--remove \
- --acl default:group:secret-project:rwx \
- --acl group:secret-project:rwx \
- --acl user:alice:--x
+ --entry default:group:secret-project:rwx \
+ --entry group:secret-project:rwx \
+ --entry user:alice:--x
__acl /srv/project2/subdir \
--default \
--remove \
- --acl group:secret-project:rwx \
- --acl user:alice:r-x
+ --entry group:secret-project:rwx \
+ --entry user:alice:r-x
+
+ # read acl from stdin
+ echo 'user:alice:rwx' \
+ | __acl /path/to/directory --source -
+
+ # create/change directory too
+ __acl /path/to/directory \
+ --default \
+ --remove \
+ --directory root:root:770 \
+ --entry user:nobody:rwx
AUTHORS
diff --git a/cdist/conf/type/__acl/manifest b/cdist/conf/type/__acl/manifest
new file mode 100755
index 00000000..5fd23110
--- /dev/null
+++ b/cdist/conf/type/__acl/manifest
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+
+for p in file directory
+do
+ [ ! -f "$__object/parameter/$p" ] && continue
+
+ "__$p" "/$__object_id" \
+ --owner "$( awk -F: '{print $1}' "$__object/parameter/$p" )" \
+ --group "$( awk -F: '{print $2}' "$__object/parameter/$p" )" \
+ --mode "$( awk -F: '{print $3}' "$__object/parameter/$p" )"
+done
diff --git a/cdist/conf/type/__acl/parameter/deprecated/acl b/cdist/conf/type/__acl/parameter/deprecated/acl
new file mode 100644
index 00000000..94e14159
--- /dev/null
+++ b/cdist/conf/type/__acl/parameter/deprecated/acl
@@ -0,0 +1 @@
+see manual for details
diff --git a/cdist/conf/type/__acl/parameter/optional b/cdist/conf/type/__acl/parameter/optional
index 4b32086b..cdcbc0b8 100644
--- a/cdist/conf/type/__acl/parameter/optional
+++ b/cdist/conf/type/__acl/parameter/optional
@@ -1,2 +1,5 @@
mask
other
+source
+file
+directory
diff --git a/cdist/conf/type/__acl/parameter/optional_multiple b/cdist/conf/type/__acl/parameter/optional_multiple
index 95c25d55..c615d507 100644
--- a/cdist/conf/type/__acl/parameter/optional_multiple
+++ b/cdist/conf/type/__acl/parameter/optional_multiple
@@ -1,3 +1,4 @@
+entry
acl
user
group
diff --git a/cdist/conf/type/__apt_unattended_upgrades/man.rst b/cdist/conf/type/__apt_unattended_upgrades/man.rst
new file mode 100644
index 00000000..2231b5f9
--- /dev/null
+++ b/cdist/conf/type/__apt_unattended_upgrades/man.rst
@@ -0,0 +1,68 @@
+cdist-type__apt_unattended_upgrades(7)
+======================================
+
+NAME
+----
+cdist-type__apt_unattended_upgrades - automatic installation of updates
+
+
+DESCRIPTION
+-----------
+
+Install and configure unattended-upgrades package.
+
+For more information see https://wiki.debian.org/UnattendedUpgrades.
+
+
+OPTIONAL MULTIPLE PARAMETERS
+----------------------------
+option
+ Set options for unattended-upgrades. See examples.
+
+ Supported options with default values (as of 2020-01-17) are:
+
+ - AutoFixInterruptedDpkg, default is "true"
+ - MinimalSteps, default is "true"
+ - InstallOnShutdown, default is "false"
+ - Mail, default is "" (empty)
+ - MailOnlyOnError, default is "false"
+ - Remove-Unused-Kernel-Packages, default is "true"
+ - Remove-New-Unused-Dependencies, default is "true"
+ - Remove-Unused-Dependencies, default is "false"
+ - Automatic-Reboot, default is "false"
+ - Automatic-Reboot-WithUsers, default is "true"
+ - Automatic-Reboot-Time, default is "02:00"
+ - SyslogEnable, default is "false"
+ - SyslogFacility, default is "daemon"
+ - OnlyOnACPower, default is "true"
+ - Skip-Updates-On-Metered-Connections, default is "true"
+ - Verbose, default is "false"
+ - Debug, default is "false"
+
+blacklist
+ Python regular expressions, matching packages to exclude from upgrading.
+
+
+EXAMPLES
+--------
+
+.. code-block:: sh
+
+ __apt_unattended_upgrades \
+ --option Mail=root \
+ --option MailOnlyOnError=true \
+ --blacklist multipath-tools \
+ --blacklist open-iscsi
+
+
+AUTHORS
+-------
+Ander Punnar
+
+
+COPYING
+-------
+Copyright \(C) 2020 Ander Punnar. 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.
diff --git a/cdist/conf/type/__apt_unattended_upgrades/manifest b/cdist/conf/type/__apt_unattended_upgrades/manifest
new file mode 100755
index 00000000..3c00e2f4
--- /dev/null
+++ b/cdist/conf/type/__apt_unattended_upgrades/manifest
@@ -0,0 +1,80 @@
+#!/bin/sh -e
+#
+# 2020 Ander Punnar (ander-at-kvlt-dot-ee)
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+
+__package unattended-upgrades
+
+export require='__package/unattended-upgrades'
+
+# in normal circumstances 20auto-upgrades is managed
+# by debconf and it can only contain these lines
+
+__file /etc/apt/apt.conf.d/20auto-upgrades \
+ --owner root \
+ --group root \
+ --mode 644 \
+ --source - << EOF
+APT::Periodic::Update-Package-Lists "1";
+APT::Periodic::Unattended-Upgrade "1";
+EOF
+
+# lets not write into upstream 50unattended-upgrades file,
+# but use our own config file to avoid clashes
+
+conf_file='/etc/apt/apt.conf.d/51unattended-upgrades-cdist'
+
+conf='# this file is managed by cdist'
+
+if [ -f "$__object/parameter/option" ]
+then
+ o=''
+
+ while read -r l
+ do
+ o="$( printf '%s\nUnattended-Upgrade::%s "%s";\n' "$o" "${l%%=*}" "${l#*=}" )"
+ done \
+ < "$__object/parameter/option"
+
+ conf="$( printf '%s\n%s\n' "$conf" "$o" )"
+fi
+
+if [ -f "$__object/parameter/blacklist" ]
+then
+ b='Unattended-Upgrade::Package-Blacklist {'
+
+ while read -r l
+ do
+ b="$( printf '%s\n"%s";\n' "$b" "$l" )"
+ done \
+ < "$__object/parameter/blacklist"
+
+ conf="$( printf '%s\n%s\n}\n' "$conf" "$b" )"
+fi
+
+if [ "$( echo "$conf" | wc -l )" -gt 1 ]
+then
+ echo "$conf" \
+ | __file "$conf_file" \
+ --owner root \
+ --group root \
+ --mode 644 \
+ --source -
+else
+ __file "$conf_file" --state absent
+fi
diff --git a/cdist/conf/type/__apt_unattended_upgrades/parameter/optional_multiple b/cdist/conf/type/__apt_unattended_upgrades/parameter/optional_multiple
new file mode 100644
index 00000000..ea4fba2b
--- /dev/null
+++ b/cdist/conf/type/__apt_unattended_upgrades/parameter/optional_multiple
@@ -0,0 +1,2 @@
+option
+blacklist
diff --git a/cdist/conf/type/__apt_unattended_upgrades/singleton b/cdist/conf/type/__apt_unattended_upgrades/singleton
new file mode 100644
index 00000000..e69de29b
diff --git a/cdist/conf/type/__cdist/manifest b/cdist/conf/type/__cdist/manifest
index a97cf288..0b0f1263 100755
--- a/cdist/conf/type/__cdist/manifest
+++ b/cdist/conf/type/__cdist/manifest
@@ -37,6 +37,7 @@ source="$(cat "$__object/parameter/source")"
# out of it
home=/home/$username
+# shellcheck disable=SC2086
__user "$username" --home "$home" $shell
require="__user/$username" __directory "$home" \
diff --git a/cdist/conf/type/__consul_agent/man.rst b/cdist/conf/type/__consul_agent/man.rst
index 966abc60..62ee70bb 100644
--- a/cdist/conf/type/__consul_agent/man.rst
+++ b/cdist/conf/type/__consul_agent/man.rst
@@ -116,6 +116,9 @@ verify-incoming
verify-outgoing
enforce the use of TLS and verify the peers authenticity on outgoing connections
+use-distribution-package
+ uses distribution package instead of upstream binary
+
EXAMPLES
--------
diff --git a/cdist/conf/type/__consul_agent/manifest b/cdist/conf/type/__consul_agent/manifest
index a88d26ed..7b54529c 100755
--- a/cdist/conf/type/__consul_agent/manifest
+++ b/cdist/conf/type/__consul_agent/manifest
@@ -1,7 +1,8 @@
#!/bin/sh -e
#
# 2015 Steven Armstrong (steven-cdist at armstrong.cc)
-# 2015-2019 Nico Schottelius (nico-cdist at schottelius.org)
+# 2015-2020 Nico Schottelius (nico-cdist at schottelius.org)
+# 2019 Timothée Floure (timothee.floure at ungleich.ch)
#
# This file is part of cdist.
#
@@ -19,133 +20,87 @@
# along with cdist. If not, see .
#
-
os=$(cat "$__global/explorer/os")
-case "$os" in
- alpine|scientific|centos|debian|devuan|redhat|ubuntu)
- # whitelist safeguard
- :
- ;;
- *)
- echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2
- echo "Please contribute an implementation for it if you can." >&2
- exit 1
- ;;
-esac
+###
+# Type parameters.
state="$(cat "$__object/parameter/state")"
user="$(cat "$__object/parameter/user")"
group="$(cat "$__object/parameter/group")"
-data_dir="/var/lib/consul"
-conf_dir="/etc/consul/conf.d"
-conf_file="config.json"
+release=$(cat "$__global/explorer/lsb_release")
+if [ -f "$__object/parameter/use-distribution-package" ]; then
+ use_distribution_package=1
+fi
-# FIXME: there has got to be a better way to handle the dependencies in this case
-case "$state" in
- present)
- __group "$group" --system --state "$state"
- require="__group/$group" \
- __user "$user" --system --gid "$group" \
- --home "$data_dir" --state "$state"
- export require="__user/consul"
- ;;
- absent)
- echo "Sorry, state=absent currently not supported :-(" >&2
- exit 1
- require="$__object_name" \
- __user "$user" --system --gid "$group" --state "$state"
- require="__user/$user" \
- __group "$group" --system --state "$state"
- ;;
+###
+# Those are default that might be overriden by os-specific logic.
+
+data_dir="/var/lib/consul"
+
+
+
+tls_dir="$conf_dir/tls"
+
+case "$os" in
+ alpine)
+ conf_dir="/etc/consul"
+ conf_file="server.json"
+ ;;
+ *)
+ conf_dir="/etc/consul/conf.d"
+ conf_file="config.json"
+ ;;
esac
-__directory /etc/consul \
- --owner root --group "$group" --mode 750 --state "$state"
-require="__directory/etc/consul" \
- __directory "$conf_dir" \
- --owner root --group "$group" --mode 750 --state "$state"
+###
+# Sane deployment, based on distribution package when available.
-if [ -f "$__object/parameter/ca-file-source" ] || [ -f "$__object/parameter/cert-file-source" ] || [ -f "$__object/parameter/key-file-source" ]; then
- # create directory for ssl certs
- require="__directory/etc/consul" \
- __directory /etc/consul/ssl \
- --owner root --group "$group" --mode 750 --state "$state"
-fi
+distribution_setup () {
+ case "$os" in
+ debian)
+ # consul is only available starting Debian 10 (buster).
+ # See https://packages.debian.org/buster/consul
+ if [ "$release" -lt 10 ]; then
+ echo "Consul is not available for your debian release." >&2
+ echo "Please use the 'manual' (i.e. non-package) installation or \
+ upgrade the target system." >&2
+ exit 1
+ fi
-__directory "$data_dir" \
- --owner "$user" --group "$group" --mode 770 --state "$state"
+ # Override previously defined environment to match debian packaging.
+ conf_dir='/etc/consul.d'
+ user='consul'
+ group='consul'
+ ;;
+ alpine)
+ # consul is only available starting Alpine 3.12 (= edge during the 3.11 cycle).
+ # See https://pkgs.alpinelinux.org/packages?name=consul&branch=edge
+ # Override previously defined environment to match alpine packaging.
+ conf_dir='/etc/consul'
+ conf_file='server.json'
+ data_dir='/var/consul'
+ user='consul'
+ group='consul'
+ ;;
+ *)
+ echo "Your operating system ($os) is currently not supported with the \
+ --use-distribution-package flag (${__type##*/})." >&2
+ echo "Please use non-package installation or contribute an \
+ implementation for if you can." >&2
+ exit 1
+ ;;
+ esac
-# Generate json config file
-(
-echo "{"
+ # Install consul package.
+ __package consul --state "$state"
-# parameters we define ourself
-printf ' "data_dir": "%s"\n' "$data_dir"
+ export config_deployment_requires="__package/consul"
+}
-cd "$__object/parameter/"
-for param in *; do
- case "$param" in
- state|user|group|json-config) continue ;;
- ca-file-source|cert-file-source|key-file-source)
- source="$(cat "$__object/parameter/$param")"
- destination="/etc/consul/ssl/${source##*/}"
- require="__directory/etc/consul/ssl" \
- __file "$destination" \
- --owner root --group consul --mode 640 \
- --source "$source" \
- --state "$state"
- key="$(echo "${param%-*}" | tr '-' '_')"
- printf ' ,"%s": "%s"\n' "$key" "$destination"
- ;;
- disable-remote-exec|disable-update-check|leave-on-terminate|rejoin-after-leave|server|enable-syslog|verify-incoming|verify-outgoing)
- # handle boolean parameters
- key="$(echo "$param" | tr '-' '_')"
- printf ' ,"%s": true\n' "$key"
- ;;
- retry-join)
- # join multiple parameters into json array
- retry_join="$(awk '{printf "\""$1"\","}' "$__object/parameter/retry-join")"
- # remove trailing ,
- printf ' ,"retry_join": [%s]\n' "${retry_join%*,}"
- ;;
- retry-join-wan)
- # join multiple parameters into json array over wan
- retry_join_wan="$(awk '{printf "\""$1"\","}' "$__object/parameter/retry-join-wan")"
- # remove trailing ,
- printf ' ,"retry_join_wan": [%s]\n' "${retry_join_wan%*,}"
- ;;
- bootstrap-expect)
- # integer key=value parameters
- key="$(echo "$param" | tr '-' '_')"
- printf ' ,"%s": %s\n' "$key" "$(cat "$__object/parameter/$param")"
- ;;
- *)
- # string key=value parameters
- key="$(echo "$param" | tr '-' '_')"
- printf ' ,"%s": "%s"\n' "$key" "$(cat "$__object/parameter/$param")"
- ;;
- esac
-done
-if [ -f "$__object/parameter/json-config" ]; then
- json_config="$(cat "$__object/parameter/json-config")"
- if [ "$json_config" = "-" ]; then
- json_config="$__object/stdin"
- fi
- # remove leading and trailing whitespace and commas from first and last line
- # indent each line with 3 spaces for consistency
- json=$(sed -e 's/^[ \t]*/ /' -e '1s/^[ \t,]*//' -e '$s/[ \t,]*$//' "$json_config")
- printf ' ,%s\n' "$json"
-fi
-echo "}"
-) | \
-require="__directory${conf_dir}" \
- __config_file "${conf_dir}/${conf_file}" \
- --owner root --group "$group" --mode 640 \
- --state "$state" \
- --onchange 'service consul status >/dev/null && service consul reload || true' \
- --source -
+###
+# LEGACY manual deployment, kept for compatibility reasons.
init_sysvinit()
{
@@ -179,47 +134,186 @@ init_upstart()
require="__file/etc/init/consul.conf" __start_on_boot consul
}
-# Install init script to start on boot
-case "$os" in
- alpine|devuan)
- init_sysvinit debian
- ;;
- centos|redhat)
- os_version="$(sed 's/[^0-9.]//g' "$__global/explorer/os_version")"
- major_version="${os_version%%.*}"
- case "$major_version" in
- [456])
- init_sysvinit redhat
- ;;
- 7)
- init_systemd
- ;;
- *)
- echo "Unsupported CentOS/Redhat version: $os_version" >&2
- exit 1
- ;;
- esac
- ;;
+manual_setup () {
+ case "$os" in
+ alpine|scientific|centos|debian|devuan|redhat|ubuntu)
+ # whitelist safeguard
+ :
+ ;;
+ *)
+ echo "Your operating system ($os) is currently not supported by this \
+ type (${__type##*/})." >&2
+ echo "Please contribute an implementation for it if you can." >&2
+ exit 1
+ ;;
+ esac
- debian)
- os_version=$(cat "$__global/explorer/os_version")
- major_version="${os_version%%.*}"
+ # FIXME: there has got to be a better way to handle the dependencies in this case
+ case "$state" in
+ present)
+ __group "$group" --system --state "$state"
+ require="__group/$group" __user "$user" \
+ --system --gid "$group" --home "$data_dir" --state "$state"
+ ;;
+ *)
+ echo "The $state state is not (yet?) supported by this type." >&2
+ exit 1
+ ;;
+ esac
- case "$major_version" in
- [567])
- init_sysvinit debian
- ;;
- [89])
- init_systemd
- ;;
- *)
- echo "Unsupported Debian version $os_version" >&2
- exit 1
- ;;
- esac
- ;;
+ # Create data directory.
+ require="__user/consul" __directory "$data_dir" \
+ --owner "$user" --group "$group" --mode 770 --state "$state"
- ubuntu)
- init_upstart
+ # Create config directory.
+ require="__user/consul" __directory "$conf_dir" \
+ --parents --owner root --group "$group" --mode 750 --state "$state"
+
+ # Install init script to start on boot
+ case "$os" in
+ devuan)
+ init_sysvinit debian
+ ;;
+ centos|redhat)
+ os_version="$(sed 's/[^0-9.]//g' "$__global/explorer/os_version")"
+ major_version="${os_version%%.*}"
+ case "$major_version" in
+ [456])
+ init_sysvinit redhat
+ ;;
+ 7)
+ init_systemd
+ ;;
+ *)
+ echo "Unsupported CentOS/Redhat version: $os_version" >&2
+ exit 1
+ ;;
+ esac
+ ;;
+
+ debian)
+ os_version=$(cat "$__global/explorer/os_version")
+ major_version="${os_version%%.*}"
+
+ case "$major_version" in
+ [567])
+ init_sysvinit debian
+ ;;
+ [89]|10)
+ init_systemd
+ ;;
+ *)
+ echo "Unsupported Debian version $os_version" >&2
+ exit 1
+ ;;
+ esac
+ ;;
+
+ ubuntu)
+ init_upstart
+ ;;
+ esac
+
+ config_deployment_requires="__user/consul __directory/$conf_dir"
+}
+
+###
+# Trigger requested installation method.
+if [ $use_distribution_package ]; then
+ distribution_setup
+else
+ manual_setup
+fi
+
+###
+# Install TLS certificates.
+
+if [ -f "$__object/parameter/ca-file-source" ] || \
+ [ -f "$__object/parameter/cert-file-source" ] || \
+ [ -f "$__object/parameter/key-file-source" ]; then
+
+ requires="$config_deployment_requires" __directory "$tls_dir" \
+ --owner root --group "$group" --mode 750 --state "$state"
+
+ # Append to service restart requirements.
+ restart_requires="$restart_requires __directory/$conf_dir/tls"
+fi
+
+###
+# Generate and deploy configuration.
+
+json_configuration=$(
+ echo "{"
+
+ # parameters we define ourself
+ printf ' "data_dir": "%s"\n' "$data_dir"
+
+ cd "$__object/parameter/"
+ for param in *; do
+ case "$param" in
+ state|user|group|json-config|use-distribution-package) continue ;;
+ ca-file-source|cert-file-source|key-file-source)
+ source="$(cat "$__object/parameter/$param")"
+ destination="$tls_dir/${source##*/}"
+ require="__directory/$tls_dir" \
+ __file "$destination" \
+ --owner root --group consul --mode 640 \
+ --source "$source" \
+ --state "$state"
+ key="$(echo "${param%-*}" | tr '-' '_')"
+ printf ' ,"%s": "%s"\n' "$key" "$destination"
;;
-esac
+ disable-remote-exec|disable-update-check|leave-on-terminate\
+ |rejoin-after-leave|server|enable-syslog|verify-incoming|verify-outgoing)
+ # handle boolean parameters
+ key="$(echo "$param" | tr '-' '_')"
+ printf ' ,"%s": true\n' "$key"
+ ;;
+ retry-join)
+ # join multiple parameters into json array
+ retry_join="$(awk '{printf "\""$1"\","}' "$__object/parameter/retry-join")"
+ # remove trailing ,
+ printf ' ,"retry_join": [%s]\n' "${retry_join%*,}"
+ ;;
+ retry-join-wan)
+ # join multiple parameters into json array over wan
+ retry_join_wan="$(awk '{printf "\""$1"\","}' "$__object/parameter/retry-join-wan")"
+ # remove trailing ,
+ printf ' ,"retry_join_wan": [%s]\n' "${retry_join_wan%*,}"
+ ;;
+ bootstrap-expect)
+ # integer key=value parameters
+ key="$(echo "$param" | tr '-' '_')"
+ printf ' ,"%s": %s\n' "$key" "$(cat "$__object/parameter/$param")"
+ ;;
+ *)
+ # string key=value parameters
+ key="$(echo "$param" | tr '-' '_')"
+ printf ' ,"%s": "%s"\n' "$key" "$(cat "$__object/parameter/$param")"
+ ;;
+ esac
+ done
+ if [ -f "$__object/parameter/json-config" ]; then
+ json_config="$(cat "$__object/parameter/json-config")"
+ if [ "$json_config" = "-" ]; then
+ json_config="$__object/stdin"
+ fi
+ # remove leading and trailing whitespace and commas from first and last line
+ # indent each line with 3 spaces for consistency
+ json=$(sed -e 's/^[ \t]*/ /' -e '1s/^[ \t,]*//' -e '$s/[ \t,]*$//' "$json_config")
+ printf ' ,%s\n' "$json"
+ fi
+ echo "}"
+)
+echo "$json_configuration" | require="$config_deployment_requires" \
+ __file "$conf_dir/$conf_file" \
+ --owner root --group "$group" --mode 640 \
+ --state "$state" \
+ --source -
+
+# Set configuration deployment as requirement for service restart.
+restart_requires="__file/$conf_dir/$conf_file"
+
+###
+# Restart consul agent after everything else.
+require="$restart_requires" __service consul --action restart
diff --git a/cdist/conf/type/__consul_agent/parameter/boolean b/cdist/conf/type/__consul_agent/parameter/boolean
index 91f7f17e..c86853c3 100644
--- a/cdist/conf/type/__consul_agent/parameter/boolean
+++ b/cdist/conf/type/__consul_agent/parameter/boolean
@@ -6,3 +6,4 @@ server
enable-syslog
verify-incoming
verify-outgoing
+use-distribution-package
diff --git a/cdist/conf/type/__consul_check/explorer/conf-dir b/cdist/conf/type/__consul_check/explorer/conf-dir
new file mode 120000
index 00000000..daa712c3
--- /dev/null
+++ b/cdist/conf/type/__consul_check/explorer/conf-dir
@@ -0,0 +1 @@
+../../__consul_service/explorer/conf-dir
\ No newline at end of file
diff --git a/cdist/conf/type/__consul_check/manifest b/cdist/conf/type/__consul_check/manifest
index c9f7add9..522aa1a9 100755
--- a/cdist/conf/type/__consul_check/manifest
+++ b/cdist/conf/type/__consul_check/manifest
@@ -19,7 +19,7 @@
#
name="$(cat "$__object/parameter/name" 2>/dev/null || echo "$__object_id")"
-conf_dir="/etc/consul/conf.d"
+conf_dir=$(cat "$__object/explorer/conf-dir")
conf_file="check_${name}.json"
state="$(cat "$__object/parameter/state")"
diff --git a/cdist/conf/type/__consul_service/explorer/conf-dir b/cdist/conf/type/__consul_service/explorer/conf-dir
new file mode 100644
index 00000000..0fc9ef84
--- /dev/null
+++ b/cdist/conf/type/__consul_service/explorer/conf-dir
@@ -0,0 +1,15 @@
+# Determine the configuration directory used by consul.
+
+check_dir () {
+ if [ -d "$1" ]; then
+ printf '%s' "$1"
+ exit
+ fi
+}
+
+check_dir '/etc/consul/conf.d'
+check_dir '/etc/consul.d'
+check_dir '/etc/consul'
+
+echo 'Could not determine consul configuration dir. Exiting.' >&2
+exit 1
diff --git a/cdist/conf/type/__consul_service/manifest b/cdist/conf/type/__consul_service/manifest
index 60397db7..d16f18e0 100755
--- a/cdist/conf/type/__consul_service/manifest
+++ b/cdist/conf/type/__consul_service/manifest
@@ -19,7 +19,7 @@
#
name="$(cat "$__object/parameter/name" 2>/dev/null || echo "$__object_id")"
-conf_dir="/etc/consul/conf.d"
+conf_dir=$(cat "$__object/explorer/conf-dir")
conf_file="service_${name}.json"
state="$(cat "$__object/parameter/state")"
@@ -45,7 +45,7 @@ printf ' "name": "%s"\n' "$name"
cd "$__object/parameter/"
for param in *; do
case "$param" in
- state|name|check-interval) continue ;;
+ state|name|check-interval|conf-dir) continue ;;
check-script)
printf ' ,"check": {\n'
printf ' "script": "%s"\n' "$(cat "$__object/parameter/check-script")"
@@ -86,7 +86,6 @@ echo " }"
# end json file
echo "}"
) | \
-require="__directory${conf_dir}" \
__config_file "${conf_dir}/${conf_file}" \
--owner root --group consul --mode 640 \
--state "$state" \
diff --git a/cdist/conf/type/__consul_watch_checks/explorer/conf-dir b/cdist/conf/type/__consul_watch_checks/explorer/conf-dir
new file mode 120000
index 00000000..daa712c3
--- /dev/null
+++ b/cdist/conf/type/__consul_watch_checks/explorer/conf-dir
@@ -0,0 +1 @@
+../../__consul_service/explorer/conf-dir
\ No newline at end of file
diff --git a/cdist/conf/type/__consul_watch_checks/manifest b/cdist/conf/type/__consul_watch_checks/manifest
index 5fdd7a74..4976b25a 100755
--- a/cdist/conf/type/__consul_watch_checks/manifest
+++ b/cdist/conf/type/__consul_watch_checks/manifest
@@ -20,7 +20,7 @@
cdist_type="${__type##*/}"
watch_type="${cdist_type##*_}"
-conf_dir="/etc/consul/conf.d"
+conf_dir=$(cat "$__object/explorer/conf-dir")
conf_file="watch_${watch_type}_${__object_id}.json"
state="$(cat "$__object/parameter/state")"
diff --git a/cdist/conf/type/__consul_watch_event/explorer/conf-dir b/cdist/conf/type/__consul_watch_event/explorer/conf-dir
new file mode 120000
index 00000000..daa712c3
--- /dev/null
+++ b/cdist/conf/type/__consul_watch_event/explorer/conf-dir
@@ -0,0 +1 @@
+../../__consul_service/explorer/conf-dir
\ No newline at end of file
diff --git a/cdist/conf/type/__consul_watch_event/manifest b/cdist/conf/type/__consul_watch_event/manifest
index 61934656..b17680c1 100755
--- a/cdist/conf/type/__consul_watch_event/manifest
+++ b/cdist/conf/type/__consul_watch_event/manifest
@@ -20,7 +20,7 @@
cdist_type="${__type##*/}"
watch_type="${cdist_type##*_}"
-conf_dir="/etc/consul/conf.d"
+conf_dir=$(cat "$__object/explorer/conf-dir")
conf_file="watch_${watch_type}_${__object_id}.json"
state="$(cat "$__object/parameter/state")"
diff --git a/cdist/conf/type/__consul_watch_key/explorer/conf-dir b/cdist/conf/type/__consul_watch_key/explorer/conf-dir
new file mode 120000
index 00000000..daa712c3
--- /dev/null
+++ b/cdist/conf/type/__consul_watch_key/explorer/conf-dir
@@ -0,0 +1 @@
+../../__consul_service/explorer/conf-dir
\ No newline at end of file
diff --git a/cdist/conf/type/__consul_watch_key/manifest b/cdist/conf/type/__consul_watch_key/manifest
index 61934656..b17680c1 100755
--- a/cdist/conf/type/__consul_watch_key/manifest
+++ b/cdist/conf/type/__consul_watch_key/manifest
@@ -20,7 +20,7 @@
cdist_type="${__type##*/}"
watch_type="${cdist_type##*_}"
-conf_dir="/etc/consul/conf.d"
+conf_dir=$(cat "$__object/explorer/conf-dir")
conf_file="watch_${watch_type}_${__object_id}.json"
state="$(cat "$__object/parameter/state")"
diff --git a/cdist/conf/type/__consul_watch_keyprefix/explorer/conf-dir b/cdist/conf/type/__consul_watch_keyprefix/explorer/conf-dir
new file mode 120000
index 00000000..daa712c3
--- /dev/null
+++ b/cdist/conf/type/__consul_watch_keyprefix/explorer/conf-dir
@@ -0,0 +1 @@
+../../__consul_service/explorer/conf-dir
\ No newline at end of file
diff --git a/cdist/conf/type/__consul_watch_keyprefix/manifest b/cdist/conf/type/__consul_watch_keyprefix/manifest
index 61934656..b17680c1 100755
--- a/cdist/conf/type/__consul_watch_keyprefix/manifest
+++ b/cdist/conf/type/__consul_watch_keyprefix/manifest
@@ -20,7 +20,7 @@
cdist_type="${__type##*/}"
watch_type="${cdist_type##*_}"
-conf_dir="/etc/consul/conf.d"
+conf_dir=$(cat "$__object/explorer/conf-dir")
conf_file="watch_${watch_type}_${__object_id}.json"
state="$(cat "$__object/parameter/state")"
diff --git a/cdist/conf/type/__consul_watch_nodes/explorer/conf-dir b/cdist/conf/type/__consul_watch_nodes/explorer/conf-dir
new file mode 120000
index 00000000..daa712c3
--- /dev/null
+++ b/cdist/conf/type/__consul_watch_nodes/explorer/conf-dir
@@ -0,0 +1 @@
+../../__consul_service/explorer/conf-dir
\ No newline at end of file
diff --git a/cdist/conf/type/__consul_watch_nodes/manifest b/cdist/conf/type/__consul_watch_nodes/manifest
index 61934656..b17680c1 100755
--- a/cdist/conf/type/__consul_watch_nodes/manifest
+++ b/cdist/conf/type/__consul_watch_nodes/manifest
@@ -20,7 +20,7 @@
cdist_type="${__type##*/}"
watch_type="${cdist_type##*_}"
-conf_dir="/etc/consul/conf.d"
+conf_dir=$(cat "$__object/explorer/conf-dir")
conf_file="watch_${watch_type}_${__object_id}.json"
state="$(cat "$__object/parameter/state")"
diff --git a/cdist/conf/type/__consul_watch_service/explorer/conf-dir b/cdist/conf/type/__consul_watch_service/explorer/conf-dir
new file mode 120000
index 00000000..daa712c3
--- /dev/null
+++ b/cdist/conf/type/__consul_watch_service/explorer/conf-dir
@@ -0,0 +1 @@
+../../__consul_service/explorer/conf-dir
\ No newline at end of file
diff --git a/cdist/conf/type/__consul_watch_service/manifest b/cdist/conf/type/__consul_watch_service/manifest
index db38eb18..e8d18328 100755
--- a/cdist/conf/type/__consul_watch_service/manifest
+++ b/cdist/conf/type/__consul_watch_service/manifest
@@ -20,7 +20,7 @@
cdist_type="${__type##*/}"
watch_type="${cdist_type##*_}"
-conf_dir="/etc/consul/conf.d"
+conf_dir=$(cat "$__object/explorer/conf-dir")
conf_file="watch_${watch_type}_${__object_id}.json"
state="$(cat "$__object/parameter/state")"
diff --git a/cdist/conf/type/__consul_watch_services/explorer/conf-dir b/cdist/conf/type/__consul_watch_services/explorer/conf-dir
new file mode 120000
index 00000000..daa712c3
--- /dev/null
+++ b/cdist/conf/type/__consul_watch_services/explorer/conf-dir
@@ -0,0 +1 @@
+../../__consul_service/explorer/conf-dir
\ No newline at end of file
diff --git a/cdist/conf/type/__consul_watch_services/manifest b/cdist/conf/type/__consul_watch_services/manifest
index 61934656..b17680c1 100755
--- a/cdist/conf/type/__consul_watch_services/manifest
+++ b/cdist/conf/type/__consul_watch_services/manifest
@@ -20,7 +20,7 @@
cdist_type="${__type##*/}"
watch_type="${cdist_type##*_}"
-conf_dir="/etc/consul/conf.d"
+conf_dir=$(cat "$__object/explorer/conf-dir")
conf_file="watch_${watch_type}_${__object_id}.json"
state="$(cat "$__object/parameter/state")"
diff --git a/cdist/conf/type/__cron/gencode-remote b/cdist/conf/type/__cron/gencode-remote
index 59398058..9debbc47 100755
--- a/cdist/conf/type/__cron/gencode-remote
+++ b/cdist/conf/type/__cron/gencode-remote
@@ -31,24 +31,28 @@ if [ -f "$__object/parameter/raw" ]; then
elif [ -f "$__object/parameter/raw_command" ]; then
entry="$command"
else
- minute="$(cat "$__object/parameter/minute" 2>/dev/null || echo "*")"
- hour="$(cat "$__object/parameter/hour" 2>/dev/null || echo "*")"
- day_of_month="$(cat "$__object/parameter/day_of_month" 2>/dev/null || echo "*")"
- month="$(cat "$__object/parameter/month" 2>/dev/null || echo "*")"
- day_of_week="$(cat "$__object/parameter/day_of_week" 2>/dev/null || echo "*")"
+ minute="$(cat "$__object/parameter/minute")"
+ hour="$(cat "$__object/parameter/hour")"
+ day_of_month="$(cat "$__object/parameter/day_of_month")"
+ month="$(cat "$__object/parameter/month")"
+ day_of_week="$(cat "$__object/parameter/day_of_week")"
entry="$minute $hour $day_of_month $month $day_of_week $command # $name"
fi
mkdir "$__object/files"
echo "$entry" > "$__object/files/entry"
-if diff -q "$__object/files/entry" "$__object/explorer/entry" >/dev/null; then
- state_is=present
+if [ -s "$__object/explorer/entry" ]; then
+ if diff -q "$__object/files/entry" "$__object/explorer/entry" >/dev/null; then
+ state_is=present
+ else
+ state_is=modified
+ fi
else
state_is=absent
fi
-state_should="$(cat "$__object/parameter/state" 2>/dev/null || echo "present")"
+state_should="$(cat "$__object/parameter/state")"
[ "$state_is" = "$state_should" ] && exit 0
diff --git a/cdist/conf/type/__cron/manifest b/cdist/conf/type/__cron/manifest
index 53973e07..e7b51863 100755
--- a/cdist/conf/type/__cron/manifest
+++ b/cdist/conf/type/__cron/manifest
@@ -22,3 +22,12 @@ if [ -f "$__object/parameter/raw" ] && [ -f "$__object/parameter/raw_command" ];
echo "ERROR: both raw and raw_command specified" >&2
exit 1
fi
+
+case "$(cat "$__object/parameter/state")" in
+ present) ;;
+ absent) ;;
+
+ *)
+ echo "ERROR: unkown cron state" >&2
+ exit 2
+esac
diff --git a/cdist/conf/type/__cron/nonparallel b/cdist/conf/type/__cron/nonparallel
new file mode 100644
index 00000000..e69de29b
diff --git a/cdist/conf/type/__cron/parameter/default/day_of_month b/cdist/conf/type/__cron/parameter/default/day_of_month
new file mode 100644
index 00000000..72e8ffc0
--- /dev/null
+++ b/cdist/conf/type/__cron/parameter/default/day_of_month
@@ -0,0 +1 @@
+*
diff --git a/cdist/conf/type/__cron/parameter/default/day_of_week b/cdist/conf/type/__cron/parameter/default/day_of_week
new file mode 100644
index 00000000..72e8ffc0
--- /dev/null
+++ b/cdist/conf/type/__cron/parameter/default/day_of_week
@@ -0,0 +1 @@
+*
diff --git a/cdist/conf/type/__cron/parameter/default/hour b/cdist/conf/type/__cron/parameter/default/hour
new file mode 100644
index 00000000..72e8ffc0
--- /dev/null
+++ b/cdist/conf/type/__cron/parameter/default/hour
@@ -0,0 +1 @@
+*
diff --git a/cdist/conf/type/__cron/parameter/default/minute b/cdist/conf/type/__cron/parameter/default/minute
new file mode 100644
index 00000000..72e8ffc0
--- /dev/null
+++ b/cdist/conf/type/__cron/parameter/default/minute
@@ -0,0 +1 @@
+*
diff --git a/cdist/conf/type/__cron/parameter/default/month b/cdist/conf/type/__cron/parameter/default/month
new file mode 100644
index 00000000..72e8ffc0
--- /dev/null
+++ b/cdist/conf/type/__cron/parameter/default/month
@@ -0,0 +1 @@
+*
diff --git a/cdist/conf/type/__cron/parameter/default/state b/cdist/conf/type/__cron/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__cron/parameter/default/state
@@ -0,0 +1 @@
+present
diff --git a/cdist/conf/type/__daemontools_service/man.rst b/cdist/conf/type/__daemontools_service/man.rst
index ec1d20ff..9bbbe2f8 100644
--- a/cdist/conf/type/__daemontools_service/man.rst
+++ b/cdist/conf/type/__daemontools_service/man.rst
@@ -40,6 +40,12 @@ run-file
log-run
Command to run for log consumption. Default: `multilog t ./main`
+owner
+ User to chown to.
+
+group
+ User to chgrp to.
+
servicedir
Directory to install into. Default: `/service`
diff --git a/cdist/conf/type/__daemontools_service/manifest b/cdist/conf/type/__daemontools_service/manifest
index 78bae285..8a81b5f5 100755
--- a/cdist/conf/type/__daemontools_service/manifest
+++ b/cdist/conf/type/__daemontools_service/manifest
@@ -9,6 +9,8 @@ servicedir=$(cat "$__object/parameter/servicedir")
run=$(cat "$__object/parameter/run")
runfile=$(cat "$__object/parameter/run-file")
logrun=$(cat "$__object/parameter/log-run")
+owner=$(cat "$__object/parameter/owner")
+group=$(cat "$__object/parameter/group")
svc=$(cat "$__type/explorer/svc")
@@ -25,14 +27,22 @@ badusage() {
[ -z "$run$runfile" ] && badusage
[ -n "$run" ] && [ -n "$runfile" ] && badusage
-__directory "$servicedir/$name/log/main" --parents
+flags=""
+if [ -n "$owner" ]; then
+ flags="$flags --owner $owner"
+fi
+if [ -n "$group" ]; then
+ flags="$flags --group $group"
+fi
+
+__directory "$servicedir/$name/log/main" --parents $flags
echo "$RUN_PREFIX$run" | require="__directory/$servicedir/$name/log/main" __config_file "$servicedir/$name/run" \
--onchange "svc -t '$servicedir/$name' 2>/dev/null" \
- --mode 755 \
+ --mode 755 $flags \
--source "${runfile:--}"
echo "$RUN_PREFIX$logrun" | require="__directory/$servicedir/$name/log/main" __config_file "$servicedir/$name/log/run" \
--onchange "svc -t '$servicedir/$name/log' 2>/dev/null" \
- --mode 755 \
+ --mode 755 $flags \
--source "-"
diff --git a/cdist/conf/type/__daemontools_service/parameter/default/group b/cdist/conf/type/__daemontools_service/parameter/default/group
new file mode 100644
index 00000000..e69de29b
diff --git a/cdist/conf/type/__daemontools_service/parameter/default/owner b/cdist/conf/type/__daemontools_service/parameter/default/owner
new file mode 100644
index 00000000..e69de29b
diff --git a/cdist/conf/type/__daemontools_service/parameter/optional b/cdist/conf/type/__daemontools_service/parameter/optional
index 7e54985f..7c66b514 100644
--- a/cdist/conf/type/__daemontools_service/parameter/optional
+++ b/cdist/conf/type/__daemontools_service/parameter/optional
@@ -1,4 +1,6 @@
+group
log-run
+owner
run
run-file
servicedir
diff --git a/cdist/conf/type/__directory/explorer/stat b/cdist/conf/type/__directory/explorer/stat
index 03d466ba..105d894f 100755
--- a/cdist/conf/type/__directory/explorer/stat
+++ b/cdist/conf/type/__directory/explorer/stat
@@ -1,6 +1,7 @@
#!/bin/sh
#
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
+# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
@@ -20,24 +21,43 @@
destination="/$__object_id"
+fallback() {
+ # Patch the output together, manually
+
+ ls_line=$(ls -ldn "$destination")
+
+ uid=$(echo "$ls_line" | awk '{ print $3 }')
+ gid=$(echo "$ls_line" | awk '{ print $4 }')
+
+ owner=$(awk -F: -v uid="$uid" '$3 == uid { print $1; f=1 } END { if (!f) print "UNKNOWN" }' /etc/passwd)
+ group=$(awk -F: -v uid="$uid" '$3 == uid { print $1; f=1 } END { if (!f) print "UNKNOWN" }' /etc/group)
+
+ mode_text=$(echo "$ls_line" | awk '{ print $1 }')
+ mode=$(echo "$mode_text" | awk '{ k=0; for (i=0; i<=8; i++) k += ((substr($1, i+2, 1) ~ /[rwx]/) * 2^(8-i)); printf("%0o", k) }')
+
+ printf 'type: %s\nowner: %d %s\ngroup: %d %s\nmode: %s %s\n' \
+ "$("$__type_explorer/type")" \
+ "$uid" "$owner" \
+ "$gid" "$group" \
+ "$mode" "$mode_text"
+}
+
# nothing to work with, nothing we could do
[ -e "$destination" ] || exit 0
-os=$("$__explorer/os")
-case "$os" in
+if ! command -v stat >/dev/null
+then
+ fallback
+ exit
+fi
+
+case $("$__explorer/os") in
"freebsd"|"netbsd"|"openbsd"|"macosx")
stat -f "type: %HT
owner: %Du %Su
group: %Dg %Sg
mode: %Lp %Sp
-" "$destination" | awk '/^type/ { print tolower($0); next; } { print; }'
- ;;
- alpine)
- stat -c "type: %F
-owner: %u %U
-group: %g %G
-mode: %a %A
-" "$destination"
+" "$destination" | awk '/^type/ { print tolower($0); next } { print }'
;;
solaris)
ls1="$( ls -ld "$destination" )"
@@ -69,10 +89,12 @@ mode: %a %A
echo "mode: $octets $( echo "$ls1" | awk '{print $1}' )"
;;
*)
- stat --printf="type: %F
+ # NOTE: Do not use --printf here as it is not supported by BusyBox stat.
+ # NOTE: BusyBox's stat might not support the "-c" option, in which case
+ # we fall through to the shell fallback.
+ stat -c "type: %F
owner: %u %U
group: %g %G
-mode: %a %A
-" "$destination"
+mode: %a %A" "$destination" 2>/dev/null || fallback
;;
esac
diff --git a/cdist/conf/type/__directory/gencode-remote b/cdist/conf/type/__directory/gencode-remote
index 374db47a..a1a32ea2 100755
--- a/cdist/conf/type/__directory/gencode-remote
+++ b/cdist/conf/type/__directory/gencode-remote
@@ -3,6 +3,7 @@
# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
# 2014 Daniel Heule (hda at sfs.biz)
+# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
@@ -21,8 +22,8 @@
#
destination="/$__object_id"
-state_should="$(cat "$__object/parameter/state")"
-type="$(cat "$__object/explorer/type")"
+state_should=$(cat "$__object/parameter/state")
+type=$(cat "$__object/explorer/type")
stat_file="$__object/explorer/stat"
# variable to keep track if we have to set directory attributes
@@ -72,7 +73,7 @@ set_mode() {
}
case "$state_should" in
- present)
+ present|exists)
if [ "$type" != "directory" ]; then
set_attributes=1
if [ "$type" != "none" ]; then
@@ -83,6 +84,10 @@ case "$state_should" in
fi
echo "mkdir $mkdiropt '$destination'"
echo "create" >> "$__messages_out"
+ elif [ "$state_should" = 'exists' ]; then
+ # The type is directory and --state exists. We are done and do not
+ # check or set the attributes.
+ exit 0
fi
# Note: Mode - needs to happen last as a chown/chgrp can alter mode by
@@ -103,6 +108,26 @@ case "$state_should" in
fi
done
;;
+ pre-exists)
+ case $type in
+ directory)
+ # all good
+ exit 0
+ ;;
+ none)
+ printf 'Directory "%s" does not exist\n' "$destination" >&2
+ exit 1
+ ;;
+ file|symlink)
+ printf 'File "%s" exists and is a %s, but should be a directory\n' "$destination" "$type" >&2
+ exit 1
+ ;;
+ *)
+ printf 'File or directory "%s" is in an unknown state\n' "$destination" >&2
+ exit 1
+ ;;
+ esac
+ ;;
absent)
if [ "$type" = "directory" ]; then
echo "rm -rf '$destination'"
diff --git a/cdist/conf/type/__directory/man.rst b/cdist/conf/type/__directory/man.rst
index 74b00afe..7755334c 100644
--- a/cdist/conf/type/__directory/man.rst
+++ b/cdist/conf/type/__directory/man.rst
@@ -19,7 +19,18 @@ None.
OPTIONAL PARAMETERS
-------------------
state
- 'present' or 'absent', defaults to 'present'
+ 'present', 'absent', 'exists' or 'pre-exists', defaults to 'present' where:
+
+ present
+ the directory exists and the given attributes are set.
+ absent
+ the directory does not exist.
+ exists
+ the directory exists, but its attributes are not altered if it already
+ existed.
+ pre-exists
+ check that the directory exists and is indeed a directory, but do not
+ create or modify it.
group
Group to chgrp to.
@@ -36,7 +47,7 @@ BOOLEAN PARAMETERS
parents
Whether to create parents as well (mkdir -p behaviour).
Warning: all intermediate directory permissions default
- to whatever mkdir -p does.
+ to whatever mkdir -p does.
Usually this means root:root, 0700.
diff --git a/cdist/conf/type/__file/explorer/stat b/cdist/conf/type/__file/explorer/stat
index 13c1c208..91c8cc84 100755
--- a/cdist/conf/type/__file/explorer/stat
+++ b/cdist/conf/type/__file/explorer/stat
@@ -2,6 +2,7 @@
#
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
# 2019 Nico Schottelius (nico-cdist at schottelius.org)
+# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
@@ -21,29 +22,54 @@
destination="/$__object_id"
+fallback() {
+ # Fallback: Patch the output together, manually.
+
+ ls_line=$(ls -ldn "$destination")
+
+ uid=$(echo "$ls_line" | awk '{ print $3 }')
+ gid=$(echo "$ls_line" | awk '{ print $4 }')
+
+ owner=$(awk -F: -v uid="$uid" '$3 == uid { print $1; f=1 } END { if (!f) print "UNKNOWN" }' /etc/passwd)
+ group=$(awk -F: -v uid="$uid" '$3 == uid { print $1; f=1 } END { if (!f) print "UNKNOWN" }' /etc/group)
+
+ mode_text=$(echo "$ls_line" | awk '{ print $1 }')
+ mode=$(echo "$mode_text" | awk '{ k=0; for (i=0; i<=8; i++) k += ((substr($1, i+2, 1) ~ /[rwx]/) * 2^(8-i)); printf("%0o", k) }')
+
+ size=$(echo "$ls_line" | awk '{ print $5 }')
+ links=$(echo "$ls_line" | awk '{ print $2 }')
+
+ printf 'type: %s\nowner: %d %s\ngroup: %d %s\nmode: %s %s\nsize: %d\nlinks: %d\n' \
+ "$("$__type_explorer/type")" \
+ "$uid" "$owner" \
+ "$gid" "$group" \
+ "$mode" "$mode_text" \
+ "$size" \
+ "$links"
+}
+
+
# nothing to work with, nothing we could do
[ -e "$destination" ] || exit 0
-os=$("$__explorer/os")
-case "$os" in
- "freebsd"|"netbsd"|"openbsd"|"macosx")
+
+if ! command -v stat >/dev/null
+then
+ fallback
+ exit
+fi
+
+
+case $("$__explorer/os")
+in
+ freebsd|netbsd|openbsd|macosx)
stat -f "type: %HT
owner: %Du %Su
group: %Dg %Sg
mode: %Lp %Sp
size: %Dz
links: %Dl
-" "$destination" | awk '/^type/ { print tolower($0); next; } { print; }'
- ;;
- alpine)
- # busybox stat
- stat -c "type: %F
-owner: %u %U
-group: %g %G
-mode: %a %A
-size: %s
-links: %h
-" "$destination"
+" "$destination" | awk '/^type/ { print tolower($0); next } { print }'
;;
solaris)
ls1="$( ls -ld "$destination" )"
@@ -77,12 +103,14 @@ links: %h
echo "links: $( echo "$ls1" | awk '{print $2}' )"
;;
*)
- stat --printf="type: %F
+ # NOTE: Do not use --printf here as it is not supported by BusyBox stat.
+ # NOTE: BusyBox's stat might not support the "-c" option, in which case
+ # we fall through to the shell fallback.
+ stat -c "type: %F
owner: %u %U
group: %g %G
mode: %a %A
size: %s
-links: %h
-" "$destination"
- ;;
+links: %h" "$destination" 2>/dev/null || fallback
+ ;;
esac
diff --git a/cdist/conf/type/__file/gencode-local b/cdist/conf/type/__file/gencode-local
index fb9f9a92..231b6927 100755
--- a/cdist/conf/type/__file/gencode-local
+++ b/cdist/conf/type/__file/gencode-local
@@ -31,12 +31,24 @@ if [ "$state_should" = "pre-exists" ]; then
exit 1
fi
- if [ "$type" = "file" ]; then
- exit 0 # nothing to do
- else
- echo "File \"$destination\" does not exist"
- exit 1
- fi
+ case $type in
+ file)
+ # nothing to do
+ exit 0
+ ;;
+ none)
+ printf 'File "%s" does not exist\n' "$destination" >&2
+ exit 1
+ ;;
+ directory|symlink)
+ printf 'File "%s" exists and is a %s, but should be a regular file\n' "$destination" "$type" >&2
+ exit 1
+ ;;
+ *)
+ printf 'File or directory "%s" is in an unknown state\n' "$destination" >&2
+ exit 1
+ ;;
+ esac
fi
upload_file=
diff --git a/cdist/conf/type/__file/gencode-remote b/cdist/conf/type/__file/gencode-remote
index b04c471e..815593bd 100755
--- a/cdist/conf/type/__file/gencode-remote
+++ b/cdist/conf/type/__file/gencode-remote
@@ -55,37 +55,41 @@ set_owner() {
}
set_mode() {
- echo "chmod '$1' '$destination'"
- echo "chmod '$1'" >> "$__messages_out"
- fire_onchange=1
+ echo "chmod '$1' '$destination'"
+ echo "chmod '$1'" >> "$__messages_out"
+ fire_onchange=1
}
case "$state_should" in
- present|exists|pre-exists)
- # Note: Mode - needs to happen last as a chown/chgrp can alter mode by
- # clearing S_ISUID and S_ISGID bits (see chown(2))
- for attribute in group owner mode; do
- if [ -f "$__object/parameter/$attribute" ]; then
- value_should="$(cat "$__object/parameter/$attribute")"
+ present|exists)
+ # Note: Mode - needs to happen last as a chown/chgrp can alter mode by
+ # clearing S_ISUID and S_ISGID bits (see chown(2))
+ for attribute in group owner mode; do
+ if [ -f "$__object/parameter/$attribute" ]; then
+ value_should="$(cat "$__object/parameter/$attribute")"
- # change 0xxx format to xxx format => same as stat returns
- if [ "$attribute" = mode ]; then
- value_should="$(echo "$value_should" | sed 's/^0\(...\)/\1/')"
- fi
-
- value_is="$(get_current_value "$attribute" "$value_should")"
- if [ -f "$__object/files/set-attributes" ] || [ "$value_should" != "$value_is" ]; then
- "set_$attribute" "$value_should"
+ # change 0xxx format to xxx format => same as stat returns
+ if [ "$attribute" = mode ]; then
+ value_should="$(echo "$value_should" | sed 's/^0\(...\)/\1/')"
+ fi
+
+ value_is="$(get_current_value "$attribute" "$value_should")"
+ if [ -f "$__object/files/set-attributes" ] || [ "$value_should" != "$value_is" ]; then
+ "set_$attribute" "$value_should"
+ fi
fi
+ done
+ if [ -f "$__object/files/set-attributes" ]; then
+ # set-attributes is created if file is created or uploaded in gencode-local
+ fire_onchange=1
fi
- done
- if [ -f "$__object/files/set-attributes" ]; then
- # set-attributes is created if file is created or uploaded in gencode-local
- fire_onchange=1
- fi
-
;;
+ pre-exists)
+ # pre-exists should never reach gencode-remote…
+ exit 1
+ ;;
+
absent)
if [ "$type" = "file" ]; then
echo "rm -f '$destination'"
@@ -101,7 +105,7 @@ case "$state_should" in
esac
if [ -f "$__object/parameter/onchange" ]; then
- if [ -n "$fire_onchange" ]; then
- cat "$__object/parameter/onchange"
- fi
+ if [ -n "$fire_onchange" ]; then
+ cat "$__object/parameter/onchange"
+ fi
fi
diff --git a/cdist/conf/type/__install_chroot_umount/manifest b/cdist/conf/type/__install_chroot_umount/manifest
new file mode 120000
index 00000000..f17af67a
--- /dev/null
+++ b/cdist/conf/type/__install_chroot_umount/manifest
@@ -0,0 +1 @@
+../__chroot_umount/manifest
\ No newline at end of file
diff --git a/cdist/conf/type/__install_directory/man.rst b/cdist/conf/type/__install_directory/man.rst
deleted file mode 120000
index 1ad7fa84..00000000
--- a/cdist/conf/type/__install_directory/man.rst
+++ /dev/null
@@ -1 +0,0 @@
-../__directory/man.rst
\ No newline at end of file
diff --git a/cdist/conf/type/__install_directory/man.rst b/cdist/conf/type/__install_directory/man.rst
new file mode 100644
index 00000000..c402cbad
--- /dev/null
+++ b/cdist/conf/type/__install_directory/man.rst
@@ -0,0 +1,101 @@
+cdist-type__install_directory(7)
+================================
+
+NAME
+----
+cdist-type__install_directory - Manage a directory with install command
+
+
+DESCRIPTION
+-----------
+This cdist type allows you to create or remove directories on the target.
+
+
+REQUIRED PARAMETERS
+-------------------
+None.
+
+
+OPTIONAL PARAMETERS
+-------------------
+state
+ 'present' or 'absent', defaults to 'present'
+
+group
+ Group to chgrp to.
+
+mode
+ Unix permissions, suitable for chmod.
+
+owner
+ User to chown to.
+
+
+BOOLEAN PARAMETERS
+------------------
+parents
+ Whether to create parents as well (mkdir -p behaviour).
+ Warning: all intermediate directory permissions default
+ to whatever mkdir -p does.
+
+ Usually this means root:root, 0700.
+
+recursive
+ If supplied the chgrp and chown call will run recursively.
+ This does *not* influence the behaviour of chmod.
+
+MESSAGES
+--------
+chgrp
+ Changed group membership
+chown
+ Changed owner
+chmod
+ Changed mode
+create
+ Empty directory was created
+remove
+ Directory exists, but state is absent, directory will be removed by generated code.
+remove non directory
+ Something other than a directory with the same name exists and was removed prior to create.
+
+
+EXAMPLES
+--------
+
+.. code-block:: sh
+
+ # A silly example
+ __install_directory /tmp/foobar
+
+ # Remove a directory
+ __install_directory /tmp/foobar --state absent
+
+ # Ensure /etc exists correctly
+ __install_directory /etc --owner root --group root --mode 0755
+
+ # Create nfs service directory, including parents
+ __install_directory /home/services/nfs --parents
+
+ # Change permissions recursively
+ __install_directory /home/services --recursive --owner root --group root
+
+ # Setup a temp directory
+ __install_directory /local --mode 1777
+
+ # Take it all
+ __install_directory /home/services/kvm --recursive --parents \
+ --owner root --group root --mode 0755 --state present
+
+
+AUTHORS
+-------
+Nico Schottelius
+
+
+COPYING
+-------
+Copyright \(C) 2011 Nico Schottelius. 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.
diff --git a/cdist/conf/type/__install_file/man.rst b/cdist/conf/type/__install_file/man.rst
index c5409167..977ed77c 100644
--- a/cdist/conf/type/__install_file/man.rst
+++ b/cdist/conf/type/__install_file/man.rst
@@ -23,6 +23,10 @@ symlink
directory
replace it with the source file
+One exception is that when state is pre-exists, an error is raised if
+the file would have been created otherwise (e.g. it is not present or
+not a regular file).
+
In any case, make sure that the file attributes are as specified.
@@ -33,7 +37,7 @@ None.
OPTIONAL PARAMETERS
-------------------
state
- 'present', 'absent' or 'exists', defaults to 'present' where:
+ 'present', 'absent', 'exists' or 'pre-exists', defaults to 'present' where:
present
the file is exactly the one from source
@@ -41,6 +45,9 @@ state
the file does not exist
exists
the file from source but only if it doesn't already exist
+ pre-exists
+ check that the file exists and is a regular file, but do not
+ create or modify it
group
Group to chgrp to.
@@ -56,6 +63,9 @@ source
If not supplied, an empty file or directory will be created.
If source is '-' (dash), take what was written to stdin as the file content.
+onchange
+ The code to run if file is modified.
+
MESSAGES
--------
chgrp
@@ -93,6 +103,8 @@ EXAMPLES
__install_file /home/frodo/.bashrc --source "/etc/skel/.bashrc" \
--state exists \
--owner frodo --mode 0600
+ # Check that the file is present, show an error when it is not
+ __install_file /etc/somefile --state pre-exists
# Take file content from stdin
__install_file /tmp/whatever --owner root --group root --mode 644 --source - << DONE
Here goes the content for /tmp/whatever
diff --git a/cdist/conf/type/__iocage_clone/gencode-remote b/cdist/conf/type/__iocage_clone/gencode-remote
new file mode 100755
index 00000000..30d77099
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/gencode-remote
@@ -0,0 +1,152 @@
+#!/bin/sh
+
+state="$(cat $__object/parameter/state)"
+template="$(cat $__object/parameter/template)"
+ip4_addr="$(cat $__object/parameter/bridge)|$(cat $__object/parameter/ip)"
+interfaces="none:none"
+defaultrouter="none"
+vnet="off"
+jail_zfs_dataset="$(cat $__object/parameter/jail_zfs_dataset)"
+devfs_ruleset="$(cat $__object/parameter/devfs_ruleset)"
+allow_socket_af="$(cat $__object/parameter/allow_socket_af)"
+mount_procfs="$(cat $__object/parameter/mount_procfs)"
+mount_linprocfs="$(cat $__object/parameter/mount_linprocfs)"
+
+if [ "X$state" = "Xabsent" ]; then
+ cat <&2
+ create_new=1
+ fi
+fi
+
+if [ \$create_new -eq 0 ]; then
+ if [ "off" == "\$(get_property_iocage jail_zfs "$__object_id")" ]; then
+ current_jail_zfs_dataset=""
+ else
+ current_jail_zfs_dataset="\$(get_property_iocage jail_zfs_dataset "$__object_id")"
+ fi
+fi
+
+configure=0
+if [ \$create_new -eq 1 ]; then
+ configure=1
+elif [ "X$vnet" != "X\$(get_property_iocage vnet "$__object_id")" ]; then
+ configure=1
+elif [ "X$ip4_addr" != "X\$(get_property_iocage ip4_addr "$__object_id")" ]; then
+ configure=1
+elif [ "X$interfaces" != "X\$(get_property_iocage interfaces "$__object_id")" ]; then
+ configure=1
+elif [ "X$defaultrouter" != "X\$(get_property_iocage defaultrouter "$__object_id")" ]; then
+ configure=1
+elif [ "X$mount_procfs" != "X\$(get_property_iocage mount_procfs "$__object_id")" ]; then
+ configure=1
+elif [ "X$devfs_ruleset" != "X\$(get_property_iocage devfs_ruleset "$__object_id")" ]; then
+ configure=1
+elif [ "X$allow_socket_af" != "X\$(get_property_iocage allow_socket_af "$__object_id")" ]; then
+ configure=1
+elif [ "X$jail_zfs_dataset" != "X\$current_jail_zfs_dataset" ]; then
+ configure=1
+fi
+
+if [ \$create_new -eq 1 ]; then
+ echo "Creating jail $__object_id" >&2
+
+ iocage stop $__object_id || true
+ iocage destroy -f $__object_id || true
+ # Without VNETs, we should not need this.
+ # TODO(riso): Use nicer path
+ # /root/cdist/ioc deconfigure $__object_id
+
+ rm -f /iocage/jails/$__object_id
+
+ iocage clone $template tag=$__object_id
+ iocage set boot=on $__object_id
+ UUID=\$(iocage list | grep " $__object_id " | awk "{ print \\\$2; }")
+ rm -f /iocage/jails/$__object_id
+ ln -s /iocage/jails/\$UUID /iocage/jails/$__object_id
+else
+ UUID=\$(iocage list | grep " $__object_id " | awk "{ print \\\$2; }")
+ echo "Jail $__object_id already exists, UUID=\$UUID" >&2
+fi
+
+ROOT="/iocage/jails/\$UUID/root"
+FSTAB="/iocage/jails/\$UUID/fstab"
+rm -f \$FSTAB.new
+touch \$FSTAB.new
+cat $__object/parameter/mount 2>/dev/null | \\
+while read mount; do
+ src=\$(echo \$mount | awk -F: "{ print \\\$1; }")
+ dst_rel=\$(echo \$mount | awk -F: "{ print \\\$2; }")
+ dst="/iocage/jails/\$UUID/root/\$dst_rel"
+ mkdir -p "\$dst"
+ echo "\$src \$dst nullfs rw 0 0" >>\$FSTAB.new
+done
+if [ $mount_linprocfs -eq 1 ]; then
+ echo "linproc /iocage/jails/\$UUID/root/compat/linux/proc linprocfs rw 0 0" >>\$FSTAB.new
+fi
+
+fstab_changed=0
+if diff -q \$FSTAB \$FSTAB.new >/dev/null; then
+ # pass
+else
+ configure=1
+ fstab_changed=1
+fi
+
+if [ \$configure -eq 1 ]; then
+ echo "Configuring jail $__object_id." >&2
+ iocage stop $__object_id || true
+
+ iocage set vnet="$vnet" $__object_id
+ iocage set interfaces="$interfaces" $__object_id
+ iocage set hostname="$__object_id" $__object_id
+ iocage set ip4_addr="$ip4_addr" $__object_id
+ iocage set defaultrouter="$defaultrouter" $__object_id
+ iocage set mount_procfs="$mount_procfs" $__object_id
+ iocage set devfs_ruleset="$devfs_ruleset" $__object_id
+ iocage set allow_socket_af="$allow_socket_af" $__object_id
+ if [ -n "$jail_zfs_dataset" ]; then
+ iocage set jail_zfs=on $__object_id
+ iocage set jail_zfs_dataset="$jail_zfs_dataset" $__object_id
+ else
+ iocage set jail_zfs=off $__object_id
+ fi
+
+ if [ \$fstab_changed -eq 1 ]; then
+ umount -afF \$FSTAB || true
+ mv \$FSTAB.new \$FSTAB
+ fi
+
+ iocage start $__object_id || true
+
+ # Iocage creates new mac address, but arp can have an old mac cached.
+ # TODO(riso): Is this true without VNETs?
+ arp -d -a
+else
+ echo "Jail $__object_id is already configured." >&2
+fi
+rm -f \$FSTAB.new
+EOF
+fi
diff --git a/cdist/conf/type/__iocage_clone/manifest b/cdist/conf/type/__iocage_clone/manifest
new file mode 100644
index 00000000..0684fce8
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/manifest
@@ -0,0 +1 @@
+__package iocage
diff --git a/cdist/conf/type/__iocage_clone/parameter/default/allow_socket_af b/cdist/conf/type/__iocage_clone/parameter/default/allow_socket_af
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/parameter/default/allow_socket_af
@@ -0,0 +1 @@
+0
diff --git a/cdist/conf/type/__iocage_clone/parameter/default/bridge b/cdist/conf/type/__iocage_clone/parameter/default/bridge
new file mode 100644
index 00000000..092f51c8
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/parameter/default/bridge
@@ -0,0 +1 @@
+bridge0
diff --git a/cdist/conf/type/__iocage_clone/parameter/default/devfs_ruleset b/cdist/conf/type/__iocage_clone/parameter/default/devfs_ruleset
new file mode 100644
index 00000000..b8626c4c
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/parameter/default/devfs_ruleset
@@ -0,0 +1 @@
+4
diff --git a/cdist/conf/type/__iocage_clone/parameter/default/jail_zfs_dataset b/cdist/conf/type/__iocage_clone/parameter/default/jail_zfs_dataset
new file mode 100644
index 00000000..e69de29b
diff --git a/cdist/conf/type/__iocage_clone/parameter/default/mount_linprocfs b/cdist/conf/type/__iocage_clone/parameter/default/mount_linprocfs
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/parameter/default/mount_linprocfs
@@ -0,0 +1 @@
+0
diff --git a/cdist/conf/type/__iocage_clone/parameter/default/mount_procfs b/cdist/conf/type/__iocage_clone/parameter/default/mount_procfs
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/parameter/default/mount_procfs
@@ -0,0 +1 @@
+0
diff --git a/cdist/conf/type/__iocage_clone/parameter/default/net b/cdist/conf/type/__iocage_clone/parameter/default/net
new file mode 100644
index 00000000..a45fd52c
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/parameter/default/net
@@ -0,0 +1 @@
+24
diff --git a/cdist/conf/type/__iocage_clone/parameter/default/state b/cdist/conf/type/__iocage_clone/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/parameter/default/state
@@ -0,0 +1 @@
+present
diff --git a/cdist/conf/type/__iocage_clone/parameter/optional b/cdist/conf/type/__iocage_clone/parameter/optional
new file mode 100644
index 00000000..8ca73ed9
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/parameter/optional
@@ -0,0 +1,7 @@
+state
+bridge
+jail_zfs_dataset
+mount_procfs
+mount_linprocfs
+devfs_ruleset
+allow_socket_af
diff --git a/cdist/conf/type/__iocage_clone/parameter/optional_multiple b/cdist/conf/type/__iocage_clone/parameter/optional_multiple
new file mode 100644
index 00000000..fde64773
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/parameter/optional_multiple
@@ -0,0 +1 @@
+mount
diff --git a/cdist/conf/type/__iocage_clone/parameter/required b/cdist/conf/type/__iocage_clone/parameter/required
new file mode 100644
index 00000000..209d1544
--- /dev/null
+++ b/cdist/conf/type/__iocage_clone/parameter/required
@@ -0,0 +1,2 @@
+ip
+template
diff --git a/cdist/conf/type/__letsencrypt_acmetiny/gencode-remote b/cdist/conf/type/__letsencrypt_acmetiny/gencode-remote
new file mode 100644
index 00000000..9243acc9
--- /dev/null
+++ b/cdist/conf/type/__letsencrypt_acmetiny/gencode-remote
@@ -0,0 +1,112 @@
+#!/bin/sh -e
+
+ACME_TINY_CERT_REQUEST_DIR="/var/acme-tiny/cert-requests"
+ACME_TINY_ACCOUNT_KEY="/var/acme-tiny/account.key"
+ACME_CHALLENGE_DIR="/srv/www/sites/acme/public/.well-known/acme-challenge"
+
+REALM="${__object_id}"
+EXTRA_DOMAINS=""
+if [ -f "${__object}/parameter/extra-domain" ]; then
+ EXTRA_DOMAINS="$(cat "${__object}/parameter/extra-domain")"
+fi
+
+#TODO: support linux too
+REALMS_DIR="/usr/local/etc/pki/realms"
+REALM_DIR="${REALMS_DIR}/${REALM}"
+REALM_CERT="${REALM_DIR}/default.crt"
+REALM_KEY="${REALM_DIR}/default.key"
+REALM_CERT_REQUEST="${ACME_TINY_CERT_REQUEST_DIR}/${REALM}.csr"
+REALM_CERT_REQUEST_CNF="${ACME_TINY_CERT_REQUEST_DIR}/${REALM}.cnf"
+
+CSR_ALT_NAMES=""
+REALM_CERT_REQUEST_CNF_LINE=""
+if [ -n "${EXTRA_DOMAINS}" ]; then
+ CSR_ALT_NAMES="DNS:${REALM}"
+ for domain in ${EXTRA_DOMAINS}; do
+ CSR_ALT_NAMES="${CSR_ALT_NAMES},DNS:${domain}"
+ done
+ # CSR requests are executed always against .new, only after succeeding .new replaces the .cnf
+ REALM_CERT_REQUEST_CNF_LINE="-reqexts SAN -config '${REALM_CERT_REQUEST_CNF}.new'"
+fi
+
+cat << EOF
+if [ ! -d '${REALM_DIR}' ]; then
+ mkdir -p '${REALM_DIR}'
+fi
+if [ ! -f '${REALM_KEY}' ]; then
+ openssl genrsa 4096 > '${REALM_KEY}'
+fi
+
+if [ ! -d '${ACME_TINY_CERT_REQUEST_DIR}' ]; then
+ mkdir '${ACME_TINY_CERT_REQUEST_DIR}'
+fi
+
+FORCE_CSR_REGEN=""
+if [ -n '${CSR_ALT_NAMES}' ]; then
+ # Generate new config
+ cat /etc/ssl/openssl.cnf > '${REALM_CERT_REQUEST_CNF}.new'
+ printf '[SAN]\nsubjectAltName=${CSR_ALT_NAMES}' >> '${REALM_CERT_REQUEST_CNF}.new'
+ # Compare to previous config if necessary
+ if [ -f '${REALM_CERT_REQUEST_CNF}' ]; then
+ CNF_DIFF=\$(diff -q '${REALM_CERT_REQUEST_CNF}' '${REALM_CERT_REQUEST_CNF}.new' || true)
+ if [ -n "\${CNF_DIFF}" ]; then
+ # Options have changed
+ FORCE_CSR_REGEN="YES"
+ else
+ # Since they match, we won't be using this, clean it
+ rm '${REALM_CERT_REQUEST_CNF}.new'
+ fi
+ else
+ # We never used SAN here, CSR regen needed.
+ FORCE_CSR_REGEN="YES"
+ fi
+else
+ # We used SAN at some point, not any more
+ if [ -f '${REALM_CERT_REQUEST_CNF}' ]; then
+ rm '${REALM_CERT_REQUEST_CNF}'
+ FORCE_CSR_REGEN="YES"
+ fi
+fi
+
+# Create or re-create when params have changed
+if [ ! -f '${REALM_CERT_REQUEST}' -o -n "\${FORCE_CSR_REGEN}" ]; then
+ openssl req -new -sha256 -key '${REALM_KEY}' -subj '/CN=${REALM}' -out '${REALM_CERT_REQUEST}' ${REALM_CERT_REQUEST_CNF_LINE}
+fi
+
+# Check if cert exists, and if so whether or not it's older than a month
+if [ -f '${REALM_CERT}' ]; then
+ MODIFIED_IN_30d="\$(find '${REALM_CERT}' -mtime -30d)"
+ if [ -z "\${MODIFIED_IN_30d}" ]; then
+ # Cert is over a month old, it's fine to regenerate
+ FORCE_CRT_REGEN="YES"
+ fi
+else
+ # This cert doesn't exist
+ FORCE_CRT_REGEN="YES"
+fi
+
+
+# Only request certificate when needed
+# TODO: support linux too
+if [ -n "\${FORCE_CSR_REGEN}" -o -n "\${FORCE_CRT_REGEN}" ]; then
+ doas -u acme-tiny -- acme_tiny \
+ --account '${ACME_TINY_ACCOUNT_KEY}' \
+ --csr '${REALM_CERT_REQUEST}' \
+ --acme-dir '${ACME_CHALLENGE_DIR}' > '${REALM_CERT}.new'
+
+ if [ -s '${REALM_CERT}.new' ]; then
+ mv '${REALM_CERT}.new' '${REALM_CERT}'
+ else
+ echo "Failed to generate cert for realm '${REALM}'."
+ exit 1
+ fi
+fi
+
+cat "${REALM_CERT}" "${REALMS_DIR}/chain.pem" > ${REALM_DIR}/fullchain.pem
+
+if [ -n '${REALM_CERT_REQUEST_CNF_LINE}' -a -f '${REALM_CERT_REQUEST_CNF}.new' ]; then
+ # CSR and cert generation succeded with a new config, put new config in-place.
+ # This is the last thing we do, so we try again next time if sth fails.
+ mv '${REALM_CERT_REQUEST_CNF}.new' '${REALM_CERT_REQUEST_CNF}'
+fi
+EOF
diff --git a/cdist/conf/type/__letsencrypt_acmetiny/manifest b/cdist/conf/type/__letsencrypt_acmetiny/manifest
new file mode 100644
index 00000000..48438abb
--- /dev/null
+++ b/cdist/conf/type/__letsencrypt_acmetiny/manifest
@@ -0,0 +1 @@
+#__letsencrypt_acmetiny_base
diff --git a/cdist/conf/type/__letsencrypt_acmetiny/nonparallel b/cdist/conf/type/__letsencrypt_acmetiny/nonparallel
new file mode 100644
index 00000000..e69de29b
diff --git a/cdist/conf/type/__letsencrypt_acmetiny/parameter/optional_multiple b/cdist/conf/type/__letsencrypt_acmetiny/parameter/optional_multiple
new file mode 100644
index 00000000..7bfb11da
--- /dev/null
+++ b/cdist/conf/type/__letsencrypt_acmetiny/parameter/optional_multiple
@@ -0,0 +1 @@
+extra-domain
diff --git a/cdist/conf/type/__letsencrypt_acmetiny_base/gencode-remote b/cdist/conf/type/__letsencrypt_acmetiny_base/gencode-remote
new file mode 100644
index 00000000..1e4174a4
--- /dev/null
+++ b/cdist/conf/type/__letsencrypt_acmetiny_base/gencode-remote
@@ -0,0 +1,12 @@
+#!/bin/sh -e
+
+ACME_HOME="/var/acme-tiny"
+ACME_ACCOUNT_KEY="${ACME_HOME}/account.key"
+
+cat << EOF
+if [ ! -f '${ACME_ACCOUNT_KEY}' ]; then
+ openssl genrsa 4096 > '${ACME_ACCOUNT_KEY}'
+ chown acme-tiny:acme-tiny '${ACME_ACCOUNT_KEY}'
+ chmod 640 '${ACME_ACCOUNT_KEY}'
+fi
+EOF
diff --git a/cdist/conf/type/__letsencrypt_acmetiny_base/manifest b/cdist/conf/type/__letsencrypt_acmetiny_base/manifest
new file mode 100644
index 00000000..cbedcdff
--- /dev/null
+++ b/cdist/conf/type/__letsencrypt_acmetiny_base/manifest
@@ -0,0 +1,227 @@
+# Arguments
+ACME_DOMAIN="$(cat "${__object}/parameter/acme_domain" || true)"
+
+if [ -z "${ACME_DOMAIN}" ]; then
+ ACME_DOMAIN="${__target_host}"
+fi
+
+
+# Install needed stuffz
+
+## TODO: consider not depending on nginx? It is... practical though.
+## TODO: Maybe just move this out to a sepecial type?
+__package "nginx"
+
+NGINX_ETC="/usr/local/etc/nginx"
+
+# Setup the acme-challenge snippet
+require="__package/nginx" __directory "${NGINX_ETC}/snippets" --state present
+require="__directory${NGINX_ETC}/snippets" __file "${NGINX_ETC}/snippets/acme-challenge.conf" \
+ --mode 644 \
+ --source - << EOF
+# This file is managed remotely, all changes will be lost
+
+# This was heavily inspired by debops.org.
+
+# Automatic Certificate Management Environment (ACME) support.
+# https://tools.ietf.org/html/draft-ietf-acme-acme-01
+# https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment
+
+
+# Return the ACME challenge present in the server public root.
+# If not found, switch to global web server root.
+location ^~ /.well-known/acme-challenge/ {
+ default_type "text/plain";
+ try_files \$uri @well-known-acme-challenge;
+}
+
+# Return the ACME challenge present in the global server public root.
+# If not present, redirect request to a specified domain.
+location @well-known-acme-challenge {
+ root /srv/www/sites/acme/public;
+ default_type "text/plain";
+ try_files \$uri @redirect-acme-challenge;
+}
+
+# Redirect the ACME challenge to a different host. If a redirect loop is
+# detected, return 404.
+location @redirect-acme-challenge {
+ if (\$arg_redirect) {
+ return 404;
+ }
+ return 307 \$scheme://${ACME_DOMAIN}\$request_uri?redirect=yes;
+}
+
+# Return 404 if ACME challenge well known path is accessed directly.
+location = /.well-known/acme-challenge/ {
+ return 404;
+}
+EOF
+
+require="__package/nginx" __directory "${NGINX_ETC}/sites-enabled" --state present
+require="__directory${NGINX_ETC}/sites-enabled" __file "${NGINX_ETC}/nginx.conf" \
+ --mode 644 \
+ --source - << EOF
+# This file is managed remotely, all changes will be lost
+
+worker_processes 1;
+
+# This default error log path is compiled-in to make sure configuration parsing
+# errors are logged somewhere, especially during unattended boot when stderr
+# isn't normally logged anywhere. This path will be touched on every nginx
+# start regardless of error log location configured here. See
+# https://trac.nginx.org/nginx/ticket/147 for more info.
+#
+#error_log /var/log/nginx/error.log;
+#
+
+#pid logs/nginx.pid;
+
+
+events {
+ worker_connections 1024;
+}
+
+
+http {
+
+ include mime.types;
+ default_type application/octet-stream;
+
+ server_tokens off;
+
+ ssl_session_cache shared:SSL:10m;
+ ssl_session_timeout 5m;
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ types_hash_max_size 2048;
+ gzip on;
+ gzip_disable "msie6";
+ gzip_comp_level 5;
+ gzip_min_length 256;
+ gzip_proxied any;
+ gzip_vary on;
+ gzip_types
+ application/atom+xml
+ application/javascript
+ application/json
+ application/ld+json
+ application/manifest+json
+ application/rss+xml
+ application/vnd.geo+json
+ application/vnd.ms-fontobject
+ application/x-font-ttf
+ application/x-web-app-manifest+json
+ application/xhtml+xml
+ application/xml
+ font/opentype
+ image/bmp
+ image/svg+xml
+ image/x-icon
+ text/cache-manifest
+ text/css
+ text/plain
+ text/vcard
+ text/vnd.rim.location.xloc
+ text/vtt
+ text/x-component
+ text/x-cross-domain-policy;
+
+ # Logging
+ access_log /var/log/nginx/access.log;
+ error_log /var/log/nginx/error.log;
+
+ #add_header X-Clacks-Overhead "GNU Terry Pratchett";
+
+ # Virtual Hosts Configs
+ include ${NGINX_ETC}/sites-enabled/*.conf;
+}
+EOF
+
+require="__directory${NGINX_ETC}/sites-enabled" __file "${NGINX_ETC}/sites-enabled/welcome.conf" \
+ --mode 644 \
+ --source - << EOF
+# This file is managed remotely, all changes will be lost
+
+# nginx server configuration for:
+# - https://welcome/
+
+server {
+
+ listen [::]:80;
+
+ server_name welcome;
+
+ root /srv/www/sites/welcome/public;
+
+ include snippets/acme-challenge.conf;
+
+ location / {
+ return 301 https://\$host\$request_uri;
+ }
+}
+EOF
+
+## TODO: this is kinda bad, don't restart every time.
+## Otherwise this isn't idempotent.
+require="__package/nginx" __service nginx --action onerestart
+require="__package/nginx" __start_on_boot nginx
+
+
+__package "acme-tiny"
+
+# Create acme-tiny user and secure home dir
+ACME_TINY_HOME="/var/acme-tiny"
+require="__package/acme-tiny" __user acme-tiny --system --home ${ACME_TINY_HOME} --comment "acme-tiny client"
+require="__user/acme-tiny" __directory "${ACME_TINY_HOME}" --state present --mode 0750 --owner acme-tiny --group acme-tiny
+
+# Create ACME challenge dirs to be served by nginx
+ACME_PUBLIC_DIR="/srv/www/sites/acme/public"
+ACME_WELLKNOWN_DIR="${ACME_PUBLIC_DIR}/.well-known"
+ACME_CHALLENGE_DIR="${ACME_WELLKNOWN_DIR}/acme-challenge"
+__directory "${ACME_PUBLIC_DIR}" \
+ --parents \
+ --state present \
+ --owner acme-tiny --group www \
+ --mode 2750 # TODO: check whether this does require gid?
+require="__directory${ACME_PUBLIC_DIR}" __directory "${ACME_WELLKNOWN_DIR}" \
+ --state present \
+ --owner acme-tiny --group www \
+ --mode 0750
+require="__directory${ACME_WELLKNOWN_DIR}" __directory "${ACME_CHALLENGE_DIR}" \
+ --state present \
+ --owner acme-tiny --group www \
+ --mode 0750
+
+__package doas
+DOAS_CONF="/usr/local/etc/doas.conf"
+require="__package/doas" __file "${DOAS_CONF}" --mode 0640
+require="__file${DOAS_CONF}" __line "${DOAS_CONF}" \
+ --regex 'root as acme-tiny' \
+ --line 'permit nopass root as acme-tiny'
+
+# Setup CA
+REALMS_DIR="/usr/local/etc/pki/realms"
+__directory "${REALMS_DIR}" \
+ --parents \
+ --state present \
+ --mode 0755
+
+require="__directory${REALMS_DIR}" __file ${REALMS_DIR}/intermediate.pem \
+ --mode 0644 \
+ --source - << EOF
+$(curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)
+EOF
+require="__directory${REALMS_DIR}" __file ${REALMS_DIR}/root.pem \
+ --mode 0644 \
+ --source - << EOF
+$(curl -s https://letsencrypt.org/certs/trustid-x3-root.pem.txt)
+EOF
+require="__directory${REALMS_DIR}" __file ${REALMS_DIR}/chain.pem \
+ --mode 0644 \
+ --source - << EOF
+$(curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem.txt)
+$(curl -s https://letsencrypt.org/certs/trustid-x3-root.pem.txt)
+EOF
+
diff --git a/cdist/conf/type/__letsencrypt_acmetiny_base/parameter/optional b/cdist/conf/type/__letsencrypt_acmetiny_base/parameter/optional
new file mode 100644
index 00000000..fb20814d
--- /dev/null
+++ b/cdist/conf/type/__letsencrypt_acmetiny_base/parameter/optional
@@ -0,0 +1 @@
+acme_domain
diff --git a/cdist/conf/type/__letsencrypt_acmetiny_base/singleton b/cdist/conf/type/__letsencrypt_acmetiny_base/singleton
new file mode 100644
index 00000000..e69de29b
diff --git a/cdist/conf/type/__letsencrypt_cert/man.rst b/cdist/conf/type/__letsencrypt_cert/man.rst
index c4ffc6bc..85eb88ea 100644
--- a/cdist/conf/type/__letsencrypt_cert/man.rst
+++ b/cdist/conf/type/__letsencrypt_cert/man.rst
@@ -59,13 +59,13 @@ MESSAGES
--------
change
- Certificte was changed.
+ Certificate was changed.
create
- Certificte was created.
+ Certificate was created.
remove
- Certificte was removed.
+ Certificate was removed.
EXAMPLES
--------
diff --git a/cdist/conf/type/__line/explorer/state b/cdist/conf/type/__line/explorer/state
index 2ef252c8..e8fc3630 100755
--- a/cdist/conf/type/__line/explorer/state
+++ b/cdist/conf/type/__line/explorer/state
@@ -1,6 +1,7 @@
#!/bin/sh -e
#
# 2018 Steven Armstrong (steven-cdist at armstrong.cc)
+# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
@@ -18,6 +19,14 @@
# along with cdist. If not, see .
#
+if [ -f "$__object/parameter/file" ]; then
+ file=$(cat "$__object/parameter/file")
+else
+ file="/$__object_id"
+fi
+
+[ -f "$file" ] || exit 0
+
if [ -f "$__object/parameter/before" ]; then
position="before"
elif [ -f "$__object/parameter/after" ]; then
@@ -33,63 +42,56 @@ else
needle="line"
fi
-if [ -f "$__object/parameter/file" ]; then
- file="$(cat "$__object/parameter/file")"
-else
- file="/$__object_id"
-fi
-
-if [ ! -f "$file" ]; then
- echo "file_missing"
- exit 0
-fi
-
awk -v position="$position" -v needle="$needle" '
function _find(_text, _pattern) {
if (needle == "regex") {
return match(_text, _pattern)
} else {
- return index(_text, _pattern)
+ return index(_text, _pattern) == 1
}
}
BEGIN {
getline anchor < (ENVIRON["__object"] "/parameter/" position)
getline pattern < (ENVIRON["__object"] "/parameter/" needle)
- state = "absent"
+
+ found_line = 0
+ correct_pos = (position != "after" && position != "before")
}
{
if (position == "after") {
if (match($0, anchor)) {
getline
if (_find($0, pattern)) {
- state = "present"
+ found_line++
+ correct_pos = 1
+ exit 0
}
- else {
- state = "wrongposition"
- }
- exit 0
+ } else if (_find($0, pattern)) {
+ found_line++
}
- }
- else if (position == "before") {
+ } else if (position == "before") {
if (_find($0, pattern)) {
+ found_line++
getline
if (match($0, anchor)) {
- state = "present"
+ correct_pos = 1
+ exit 0
}
- else {
- state = "wrongposition"
- }
- exit 0
}
- }
- else {
+ } else {
if (_find($0, pattern)) {
- state = "present"
+ found_line++
exit 0
}
}
}
END {
- print state
+ if (found_line && correct_pos) {
+ print "present"
+ } else if (found_line) {
+ print "wrongposition"
+ } else {
+ print "absent"
+ }
}
' "$file"
diff --git a/cdist/conf/type/__line/gencode-remote b/cdist/conf/type/__line/gencode-remote
index 03e90c1b..88cae68b 100755
--- a/cdist/conf/type/__line/gencode-remote
+++ b/cdist/conf/type/__line/gencode-remote
@@ -1,6 +1,7 @@
#!/bin/sh -e
#
# 2018 Steven Armstrong (steven-cdist at armstrong.cc)
+# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch)
#
# This file is part of cdist.
#
@@ -23,9 +24,20 @@ if [ -f "$__object/parameter/before" ] && [ -f "$__object/parameter/after" ]; th
exit 1
fi
+if [ -f "$__object/parameter/file" ]; then
+ file="$(cat "$__object/parameter/file")"
+else
+ file="/$__object_id"
+fi
+
state_should="$(cat "$__object/parameter/state")"
state_is="$(cat "$__object/explorer/state")"
+if [ -z "$state_is" ]; then
+ printf 'The file "%s" is missing. Please create it before using %s on it.\n' "$file" "${__type##*/}" >&2
+ exit 1
+fi
+
if [ "$state_should" = "$state_is" ]; then
# nothing to do
exit 0
@@ -46,12 +58,6 @@ else
needle="line"
fi
-if [ -f "$__object/parameter/file" ]; then
- file="$(cat "$__object/parameter/file")"
-else
- file="/$__object_id"
-fi
-
add=0
remove=0
case "$state_should" in
@@ -104,10 +110,12 @@ BEGIN {
if (anchor && match(\$0, anchor)) {
if (position == "before") {
print line
+ add = 0
print
} else if (position == "after") {
print
print line
+ add = 0
}
next
}
@@ -115,7 +123,7 @@ BEGIN {
print
}
END {
- if (add && position == "end") {
+ if (add) {
print line
}
}
diff --git a/cdist/conf/type/__motd/gencode-remote b/cdist/conf/type/__motd/gencode-remote
index bc842cc8..738ea834 100755
--- a/cdist/conf/type/__motd/gencode-remote
+++ b/cdist/conf/type/__motd/gencode-remote
@@ -29,7 +29,18 @@ case "$os" in
echo "uname -snrvm > /var/run/motd"
echo "cat /etc/motd.tail >> /var/run/motd"
;;
+ freebsd)
+ # FreeBSD only updates /etc/motd on boot,
+ # as seen in /etc/rc.d/motd
+ echo "uname -sri > /etc/motd"
+ echo "cat /etc/motd.template >> /etc/motd"
+ # FreeBSD 13 starts treating motd slightly different from previous
+ # versions this ensures hosts have the expected config.
+ echo "rm /etc/motd.template || true"
+ echo "service motd start"
+ ;;
*)
+ # Other OS tend to treat /etc/motd statically
exit 0
;;
esac
diff --git a/cdist/conf/type/__motd/man.rst b/cdist/conf/type/__motd/man.rst
index 17369684..a567dc80 100644
--- a/cdist/conf/type/__motd/man.rst
+++ b/cdist/conf/type/__motd/man.rst
@@ -10,6 +10,13 @@ DESCRIPTION
-----------
This cdist type allows you to easily setup /etc/motd.
+.. note::
+ In some OS, motd is a bit special, check `motd(5)`.
+ Currently Debian, Devuan, Ubuntu and FreeBSD are taken into account.
+ If your OS of choice does something besides /etc/motd, check the source
+ and contribute support for it.
+ Otherwise it will likely just work.
+
REQUIRED PARAMETERS
-------------------
@@ -20,6 +27,7 @@ OPTIONAL PARAMETERS
-------------------
source
If supplied, copy this file from the host running cdist to the target.
+ If source is '-' (dash), take what was written to stdin as the file content.
If not supplied, a default message will be placed onto the target.
@@ -34,6 +42,15 @@ EXAMPLES
# Supply source file from a different type
__motd --source "$__type/files/my-motd"
+ # Supply source from stdin
+ __motd --source "-" <
COPYING
-------
-Copyright \(C) 2011 Nico Schottelius. You can redistribute it
+Copyright \(C) 2020 Nico Schottelius. 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.
diff --git a/cdist/conf/type/__motd/manifest b/cdist/conf/type/__motd/manifest
index cd741cf4..ded734d7 100755
--- a/cdist/conf/type/__motd/manifest
+++ b/cdist/conf/type/__motd/manifest
@@ -34,9 +34,17 @@ os=$(cat "$__global/explorer/os")
case "$os" in
debian|ubuntu|devuan)
+ # Debian-based systems use /etc/motd.tail as a template
destination=/etc/motd.tail
;;
+ freebsd)
+ # FreeBSD uses motd.template to prepend system information on boot
+ # (this actually only applies starting with version 13,
+ # but we fix that for whatever version in gencode-remote)
+ destination=/etc/motd.template
+ ;;
*)
+ # Most UNIX systems, including other Linux and OpenBSD just use /etc/motd
destination=/etc/motd
;;
esac
diff --git a/cdist/conf/type/__mysql_database/explorer/state b/cdist/conf/type/__mysql_database/explorer/state
new file mode 100755
index 00000000..79858695
--- /dev/null
+++ b/cdist/conf/type/__mysql_database/explorer/state
@@ -0,0 +1,33 @@
+#!/bin/sh -e
+#
+# 2020 Ander Punnar (ander-at-kvlt-dot-ee)
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+
+if [ -f "$__object/parameter/name" ]
+then
+ name="$( cat "$__object/parameter/name" )"
+else
+ name="$__object_id"
+fi
+
+if [ -n "$( mysql -B -N -e "show databases like '$name'" )" ]
+then
+ echo 'present'
+else
+ echo 'absent'
+fi
diff --git a/cdist/conf/type/__mysql_database/gencode-remote b/cdist/conf/type/__mysql_database/gencode-remote
index 23e51b05..1bdb2b11 100755
--- a/cdist/conf/type/__mysql_database/gencode-remote
+++ b/cdist/conf/type/__mysql_database/gencode-remote
@@ -1,6 +1,6 @@
#!/bin/sh -e
#
-# 2012 Benedikt Koeppel (code@benediktkoeppel.ch)
+# 2020 Ander Punnar (ander-at-kvlt-dot-ee)
#
# This file is part of cdist.
#
@@ -17,38 +17,30 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see .
#
-#
-# if --database was specified
-if [ -f "$__object/parameter/name" ]; then
- database="$(cat "$__object/parameter/name")"
-else # otherwise use the object id as database name
- database="$__object_id"
+state_is="$( cat "$__object/explorer/state" )"
+
+state_should="$( cat "$__object/parameter/state" )"
+
+if [ "$state_is" = "$state_should" ]
+then
+ exit 0
fi
-cat <<-EOFF
-mysql -u root <<-EOF
- CREATE DATABASE IF NOT EXISTS $database
-EOF
-EOFF
-
-# if --user was specified
-if [ -f "$__object/parameter/user" ]; then
- user="$(cat "$__object/parameter/user")"
-
- # if --password was specified
- if [ -f "$__object/parameter/password" ]; then
- password="$(cat "$__object/parameter/password")"
- cat <<-EOFF
- mysql -u root <<-EOF
- GRANT ALL PRIVILEGES ON $database.* to '$user'@'localhost' IDENTIFIED BY '$password';
-EOF
-EOFF
- else
- cat <<-EOFF
- mysql -u root <<-EOF
- GRANT ALL PRIVILEGES ON $database.* to '$user'@'localhost';
-EOF
-EOFF
- fi
+if [ -f "$__object/parameter/name" ]
+then
+ name="$( cat "$__object/parameter/name" )"
+else
+ name="$__object_id"
fi
+
+case "$state_should" in
+ present)
+ echo "mysql -e 'create database \`$name\`'"
+ echo "create database $name" >> "$__messages_out"
+ ;;
+ absent)
+ echo "mysql -e 'drop database \`$name\`'"
+ echo "drop database $name" >> "$__messages_out"
+ ;;
+esac
diff --git a/cdist/conf/type/__mysql_database/man.rst b/cdist/conf/type/__mysql_database/man.rst
index 1e245a08..b3b56b5f 100644
--- a/cdist/conf/type/__mysql_database/man.rst
+++ b/cdist/conf/type/__mysql_database/man.rst
@@ -8,24 +8,24 @@ cdist-type__mysql_database - Manage a MySQL database
DESCRIPTION
-----------
-This cdist type allows you to install a MySQL database.
+Create MySQL database and optionally user with all privileges.
-REQUIRED PARAMETERS
--------------------
-None.
OPTIONAL PARAMETERS
-------------------
name
- The name of the database to install
- defaults to the object id
+ Name of database. Defaults to object id.
user
- A user that should have access to the database
+ Create user and give all privileges to database.
password
- The password for the user who manages the database
+ Password for user.
+
+state
+ Defaults to present.
+ If absent and user is also set, both will be removed (with privileges).
EXAMPLES
@@ -33,17 +33,23 @@ EXAMPLES
.. code-block:: sh
- __mysql_database "cdist" --name "cdist" --user "myuser" --password "mypwd"
+ # just create database
+ __mysql_database foo
+
+ # create database with respective user with all privileges to database
+ __mysql_database bar \
+ --user name \
+ --password secret
AUTHORS
-------
-Benedikt Koeppel
+Ander Punnar
COPYING
-------
-Copyright \(C) 2012 Benedikt Koeppel. 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.
+Copyright \(C) 2020 Ander Punnar. 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.
diff --git a/cdist/conf/type/__mysql_database/manifest b/cdist/conf/type/__mysql_database/manifest
new file mode 100755
index 00000000..a3c9ed5d
--- /dev/null
+++ b/cdist/conf/type/__mysql_database/manifest
@@ -0,0 +1,52 @@
+#!/bin/sh -e
+#
+# 2020 Ander Punnar (ander-at-kvlt-dot-ee)
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+
+if [ -f "$__object/parameter/user" ]
+then
+ user="$( cat "$__object/parameter/user" )"
+fi
+
+if [ -f "$__object/parameter/password" ]
+then
+ password="$( cat "$__object/parameter/password" )"
+fi
+
+if [ -n "$user" ] && [ -n "$password" ]
+then
+ if [ -f "$__object/parameter/name" ]
+ then
+ database="$( cat "$__object/parameter/name" )"
+ else
+ database="$__object_id"
+ fi
+
+ state_should="$( cat "$__object/parameter/state" )"
+
+ __mysql_user "$user" \
+ --password "$password" \
+ --state "$state_should"
+
+ # removing user should remove all user's privileges
+ require="__mysql_user/$user" \
+ __mysql_privileges "$database/$user" \
+ --database "$database" \
+ --user "$user" \
+ --state "$state_should"
+fi
diff --git a/cdist/conf/type/__mysql_database/parameter/default/state b/cdist/conf/type/__mysql_database/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__mysql_database/parameter/default/state
@@ -0,0 +1 @@
+present
diff --git a/cdist/conf/type/__mysql_database/parameter/optional b/cdist/conf/type/__mysql_database/parameter/optional
index 756afee7..6c0b1e85 100644
--- a/cdist/conf/type/__mysql_database/parameter/optional
+++ b/cdist/conf/type/__mysql_database/parameter/optional
@@ -1,3 +1,4 @@
name
user
password
+state
diff --git a/cdist/conf/type/__mysql_privileges/explorer/state b/cdist/conf/type/__mysql_privileges/explorer/state
new file mode 100755
index 00000000..4f13a70c
--- /dev/null
+++ b/cdist/conf/type/__mysql_privileges/explorer/state
@@ -0,0 +1,40 @@
+#!/bin/sh -e
+#
+# 2020 Ander Punnar (ander-at-kvlt-dot-ee)
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+
+privileges="$( cat "$__object/parameter/privileges" )"
+
+database="$( cat "$__object/parameter/database" )"
+
+table="$( cat "$__object/parameter/table" )"
+
+user="$( cat "$__object/parameter/user" )"
+
+host="$( cat "$__object/parameter/host" )"
+
+check_privileges="$(
+ mysql -B -N -e "show grants for '$user'@'$host'" \
+ | grep -Ei "^grant $privileges on .$database.\..?$table.? to " || true )"
+
+if [ -n "$check_privileges" ]
+then
+ echo 'present'
+else
+ echo 'absent'
+fi
diff --git a/cdist/conf/type/__mysql_privileges/gencode-remote b/cdist/conf/type/__mysql_privileges/gencode-remote
new file mode 100755
index 00000000..0656699f
--- /dev/null
+++ b/cdist/conf/type/__mysql_privileges/gencode-remote
@@ -0,0 +1,55 @@
+#!/bin/sh -e
+#
+# 2020 Ander Punnar (ander-at-kvlt-dot-ee)
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+
+state_is="$( cat "$__object/explorer/state" )"
+
+state_should="$( cat "$__object/parameter/state" )"
+
+if [ "$state_is" = "$state_should" ]
+then
+ exit 0
+fi
+
+privileges="$( cat "$__object/parameter/privileges" )"
+
+database="$( cat "$__object/parameter/database" )"
+
+table="$( cat "$__object/parameter/table" )"
+
+user="$( cat "$__object/parameter/user" )"
+
+host="$( cat "$__object/parameter/host" )"
+
+if [ "$table" != '*' ]
+then
+ # shellcheck disable=SC2016
+ table="$( printf '`%s`' "$table" )"
+fi
+
+case "$state_should" in
+ present)
+ echo "mysql -e 'grant $privileges on \`$database\`.$table to \`$user\`@\`$host\`'"
+ echo "grant $privileges on $database.$table to $user@$host" >> "$__messages_out"
+ ;;
+ absent)
+ echo "mysql -e 'revoke $privileges on \`$database\`.$table from \`$user\`@\`$host\`'"
+ echo "revoke $privileges on $database.$table from $user@$host" >> "$__messages_out"
+ ;;
+esac
diff --git a/cdist/conf/type/__mysql_privileges/man.rst b/cdist/conf/type/__mysql_privileges/man.rst
new file mode 100644
index 00000000..b72c9eba
--- /dev/null
+++ b/cdist/conf/type/__mysql_privileges/man.rst
@@ -0,0 +1,57 @@
+cdist-type__mysql_privileges(7)
+===============================
+
+NAME
+----
+cdist-type__mysql_privileges - Manage MySQL privileges
+
+
+DESCRIPTION
+-----------
+
+Grant and revoke privileges of MySQL user.
+
+
+REQUIRED PARAMETERS
+-------------------
+database
+ Name of database.
+
+user
+ Name of user.
+
+
+OPTIONAL PARAMETERS
+-------------------
+privileges
+ Defaults to "all".
+
+table
+ Defaults to "*".
+
+host
+ Defaults to localhost.
+
+state
+ "present" grants and "absent" revokes. Defaults to present.
+
+
+EXAMPLES
+--------
+
+.. code-block:: sh
+
+ __mysql_privileges user-to-db --database db --user user
+
+
+AUTHORS
+-------
+Ander Punnar
+
+
+COPYING
+-------
+Copyright \(C) 2020 Ander Punnar. 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.
diff --git a/cdist/conf/type/__mysql_privileges/parameter/default/host b/cdist/conf/type/__mysql_privileges/parameter/default/host
new file mode 100644
index 00000000..2fbb50c4
--- /dev/null
+++ b/cdist/conf/type/__mysql_privileges/parameter/default/host
@@ -0,0 +1 @@
+localhost
diff --git a/cdist/conf/type/__mysql_privileges/parameter/default/privileges b/cdist/conf/type/__mysql_privileges/parameter/default/privileges
new file mode 100644
index 00000000..5472efad
--- /dev/null
+++ b/cdist/conf/type/__mysql_privileges/parameter/default/privileges
@@ -0,0 +1 @@
+all privileges
diff --git a/cdist/conf/type/__mysql_privileges/parameter/default/state b/cdist/conf/type/__mysql_privileges/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__mysql_privileges/parameter/default/state
@@ -0,0 +1 @@
+present
diff --git a/cdist/conf/type/__mysql_privileges/parameter/default/table b/cdist/conf/type/__mysql_privileges/parameter/default/table
new file mode 100644
index 00000000..72e8ffc0
--- /dev/null
+++ b/cdist/conf/type/__mysql_privileges/parameter/default/table
@@ -0,0 +1 @@
+*
diff --git a/cdist/conf/type/__mysql_privileges/parameter/optional b/cdist/conf/type/__mysql_privileges/parameter/optional
new file mode 100644
index 00000000..d4ed5bc5
--- /dev/null
+++ b/cdist/conf/type/__mysql_privileges/parameter/optional
@@ -0,0 +1,4 @@
+privileges
+table
+host
+state
diff --git a/cdist/conf/type/__mysql_privileges/parameter/required b/cdist/conf/type/__mysql_privileges/parameter/required
new file mode 100644
index 00000000..152b4a1e
--- /dev/null
+++ b/cdist/conf/type/__mysql_privileges/parameter/required
@@ -0,0 +1,2 @@
+database
+user
diff --git a/cdist/conf/type/__mysql_user/explorer/state b/cdist/conf/type/__mysql_user/explorer/state
new file mode 100755
index 00000000..6817ee9d
--- /dev/null
+++ b/cdist/conf/type/__mysql_user/explorer/state
@@ -0,0 +1,54 @@
+#!/bin/sh -e
+#
+# 2020 Ander Punnar (ander-at-kvlt-dot-ee)
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+
+if [ -f "$__object/parameter/name" ]
+then
+ name="$( cat "$__object/parameter/name" )"
+else
+ name="$__object_id"
+fi
+
+if [ -f "$__object/parameter/password" ]
+then
+ password="$( cat "$__object/parameter/password" )"
+else
+ password=''
+fi
+
+host="$( cat "$__object/parameter/host" )"
+
+check_user="$( mysql -B -N -e "select user from mysql.user where user = '$name' and host = '$host'" )"
+
+if [ -n "$check_user" ]
+then
+ if [ -n "$password" ]
+ then
+ check_password="$( mysql -B -N -e "select user from mysql.user where user = '$name' and host = '$host' and password = password( '$password' )" )"
+ fi
+
+ if [ -n "$password" ] && [ -z "$check_password" ]
+ then
+ echo 'change-password'
+ else
+ echo 'present'
+ fi
+else
+ echo 'absent'
+fi
diff --git a/cdist/conf/type/__mysql_user/gencode-remote b/cdist/conf/type/__mysql_user/gencode-remote
new file mode 100755
index 00000000..5f13bc87
--- /dev/null
+++ b/cdist/conf/type/__mysql_user/gencode-remote
@@ -0,0 +1,68 @@
+#!/bin/sh -e
+#
+# 2020 Ander Punnar (ander-at-kvlt-dot-ee)
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+
+state_is="$( cat "$__object/explorer/state" )"
+
+state_should="$( cat "$__object/parameter/state" )"
+
+if [ "$state_is" = "$state_should" ]
+then
+ exit 0
+fi
+
+if [ -f "$__object/parameter/name" ]
+then
+ name="$( cat "$__object/parameter/name" )"
+else
+ name="$__object_id"
+fi
+
+host="$( cat "$__object/parameter/host" )"
+
+if [ -f "$__object/parameter/password" ]
+then
+ password="$( cat "$__object/parameter/password" )"
+else
+ if [ "$state_should" = 'present' ]
+ then
+ echo '--password needed' >&2
+ exit 1
+ else
+ password=''
+ fi
+fi
+
+if [ "$state_is" = 'absent' ] && [ "$state_should" = 'present' ]
+then
+ echo "mysql -e 'create user \`$name\`@\`$host\` identified by \"$password\"'"
+ echo "create user $name@$host" >> "$__messages_out"
+
+elif [ "$state_is" != 'absent' ] && [ "$state_should" = 'absent' ]
+then
+ echo "mysql -e 'drop user \`$name\`@\`$host\`'"
+ echo "drop user $name@$host" >> "$__messages_out"
+
+elif [ "$state_is" = 'change-password' ]
+then
+ # this only works with MySQL 5.7.6 and later or MariaDB 10.1.20 and later
+ echo "mysql -e 'alter user \`$name\`@\`$host\` identified by \"$password\"'"
+ echo "mysql -e 'flush privileges'"
+ echo "change password $name@$host" >> "$__messages_out"
+fi
diff --git a/cdist/conf/type/__mysql_user/man.rst b/cdist/conf/type/__mysql_user/man.rst
new file mode 100644
index 00000000..c2b222d5
--- /dev/null
+++ b/cdist/conf/type/__mysql_user/man.rst
@@ -0,0 +1,48 @@
+cdist-type__mysql_user(7)
+=========================
+
+NAME
+----
+cdist-type__mysql_user - Manage a MySQL user
+
+
+DESCRIPTION
+-----------
+
+Create MySQL user or change password for the user.
+
+
+OPTIONAL PARAMETERS
+-------------------
+name
+ Name of user. Defaults to object id.
+
+host
+ Host of user. Defaults to localhost.
+
+password
+ Password of user.
+
+state
+ Defaults to present.
+
+
+EXAMPLES
+--------
+
+.. code-block:: sh
+
+ __mysql_user user --password secret
+
+
+AUTHORS
+-------
+Ander Punnar
+
+
+COPYING
+-------
+Copyright \(C) 2020 Ander Punnar. 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.
diff --git a/cdist/conf/type/__mysql_user/parameter/default/host b/cdist/conf/type/__mysql_user/parameter/default/host
new file mode 100644
index 00000000..2fbb50c4
--- /dev/null
+++ b/cdist/conf/type/__mysql_user/parameter/default/host
@@ -0,0 +1 @@
+localhost
diff --git a/cdist/conf/type/__mysql_user/parameter/default/state b/cdist/conf/type/__mysql_user/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__mysql_user/parameter/default/state
@@ -0,0 +1 @@
+present
diff --git a/cdist/conf/type/__mysql_user/parameter/optional b/cdist/conf/type/__mysql_user/parameter/optional
new file mode 100644
index 00000000..a286266c
--- /dev/null
+++ b/cdist/conf/type/__mysql_user/parameter/optional
@@ -0,0 +1,4 @@
+name
+host
+password
+state
diff --git a/cdist/conf/type/__openldap_server/gencode-remote b/cdist/conf/type/__openldap_server/gencode-remote
new file mode 100644
index 00000000..b1e98f8c
--- /dev/null
+++ b/cdist/conf/type/__openldap_server/gencode-remote
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+manager_dn=$(cat "${__object}/parameter/manager-dn")
+manager_password=$(cat "${__object}/parameter/manager-password")
+description=$(cat "${__object}/parameter/description")
+suffix=$(cat "${__object}/parameter/suffix")
+suffix_dc=$(printf "%s" "${suffix}" | awk -F',' '{print $1}' | awk -F'=' '{print $2}')
+
+SLAPD_IPC=$(tr '\n' ' ' < "${__object}/parameter/slapd-url" | awk '{ print $1}')
+
+cat <&1 > /dev/null; then
+ # Already exists, use ldapmodify
+ ldapmodify -xZ -D "${manager_dn}" -w "${manager_password}" -H '${SLAPD_IPC}' <
+Evilham
+
+
+COPYING
+-------
+Copyright \(C) 2020 ungleich glarus ag. 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.
diff --git a/cdist/conf/type/__openldap_server/manifest b/cdist/conf/type/__openldap_server/manifest
new file mode 100644
index 00000000..84ba176f
--- /dev/null
+++ b/cdist/conf/type/__openldap_server/manifest
@@ -0,0 +1,267 @@
+#!/bin/sh
+
+name="${__target_host}"
+manager_dn=$(cat "${__object}/parameter/manager-dn")
+manager_password_hash=$(cat "${__object}/parameter/manager-password-hash")
+serverid=$(cat "${__object}/parameter/serverid")
+suffix=$(cat "${__object}/parameter/suffix")
+slapd_modules=$(cat "${__object}/parameter/module" 2>/dev/null || true)
+schemas=$(cat "${__object}/parameter/schema")
+slapd_urls=$(tr '\n' ' ' < "${__object}/parameter/slapd-url")
+tls_cipher_suite=$(cat "${__object}/parameter/tls-cipher-suite" 2>/dev/null || true)
+extra_config=$(cat "${__object}/parameter/extra-config" || true)
+
+
+os="$(cat "${__global}/explorer/os")"
+
+# Setup OS-dependent vars
+CONF_OWNER="root"
+CONF_GROUP="root"
+case "${os}" in
+ freebsd)
+ PKGS="openldap-server"
+ ETC="/usr/local/etc"
+ SLAPD_DIR="/usr/local/etc/openldap"
+ SLAPD_DATA_DIR="/var/db/openldap-data"
+ SLAPD_RUN_DIR="/var/run/openldap"
+ SLAPD_MODULE_PATH="/usr/local/libexec/openldap"
+ if [ -z "${slapd_modules}" ]; then
+ # It looks like ppolicy and syncprov must be compiled
+ slapd_modules="back_mdb back_monitor"
+ fi
+ CONF_OWNER="ldap"
+ CONF_GROUP="ldap"
+ if [ -z "${tls_cipher_suite}" ]; then
+ # TODO: research default for FreeBSD. 'NORMAL' appears to not work
+ tls_cipher_suite="HIGH:MEDIUM:+SSLv2"
+ fi
+ ;;
+ debian|ubuntu|devuan)
+ PKGS="slapd ldap-utils"
+ ETC="/etc"
+ SLAPD_DIR="/etc/ldap"
+ SLAPD_DATA_DIR="/var/lib/ldap"
+ SLAPD_RUN_DIR="/var/run/slapd"
+ SLAPD_MODULE_PATH="/usr/lib/ldap"
+ if [ -z "${slapd_modules}" ]; then
+ slapd_modules="back_mdb ppolicy syncprov back_monitor"
+ fi
+ if [ -z "${tls_cipher_suite}" ]; then
+ tls_cipher_suite="NORMAL"
+ fi
+ ;;
+ *)
+ echo "Don't know the openldap defaults for: $os" >&2
+ exit 1
+ ;;
+esac
+
+PKG_MAIN=$(echo "${PKGS}" | awk '{print $1;}')
+
+
+# Determine if __letsencrypt_cert is to be used and setup vars accordingly
+if [ -f "${__object}/parameter/tls-cert" ]; then
+ tls_cert=$(cat "${__object}/parameter/tls-cert")
+
+ if [ ! -f "${__object}/parameter/tls-privkey" ]; then
+ echo "When tls-cert is defined, tls-privkey is also required." >&2
+ exit 1
+ fi
+ tls_privkey=$(cat "${__object}/parameter/tls-privkey")
+
+ if [ ! -f "${__object}/parameter/tls-ca" ]; then
+ echo "When tls-cert is defined, tls-ca is also required." >&2
+ exit 1
+ fi
+ tls_ca=$(cat "${__object}/parameter/tls-ca")
+
+ _skip_letsencrypt_cert="YES"
+else
+ if [ ! -f "${__object}/parameter/admin-email" ]; then
+ echo "When using __letsencrypt_cert, admin-email is also required." >&2
+ exit 1
+ fi
+ admin_email=$(cat "${__object}/parameter/admin-email")
+
+ tls_cert="${SLAPD_DIR}/sasl2/cert.pem"
+ tls_privkey="${SLAPD_DIR}/sasl2/privkey.pem"
+ tls_ca="${SLAPD_DIR}/sasl2/chain.pem"
+fi
+
+mkdir "${__object}/files"
+ldapconf="${__object}/files/ldapconf"
+
+replication=""
+if [ -f "${__object}/parameter/replicate" ]; then
+ replication=yes
+
+ if [ ! -f "${__object}/parameter/syncrepl-searchbase" ]; then
+ echo "Requiring the searchbase for replication" >&2
+ exit 1
+ fi
+ syncrepl_searchbase=$(cat "${__object}/parameter/syncrepl-searchbase")
+
+ if [ ! -f "${__object}/parameter/syncrepl-credentials" ]; then
+ echo "Requiring credentials for replication" >&2
+ exit 1
+ fi
+
+ syncrepl_credentials=$(cat "${__object}/parameter/syncrepl-credentials")
+
+ if [ ! -f "${__object}/parameter/syncrepl-host" ]; then
+ echo "Requiring host(s) for replication" >&2
+ exit 1
+ fi
+ syncrepl_hosts=$(cat "${__object}/parameter/syncrepl-host")
+
+fi
+
+# Install required packages
+for pkg in ${PKGS}; do
+ __package "${pkg}"
+done
+
+
+require="__package/${PKG_MAIN}" __start_on_boot slapd
+
+# Setup -h flag for the listeners. See man slapd (-h flag).
+case "${os}" in
+ freebsd)
+ require="__start_on_boot/slapd" __key_value \
+ --file "/etc/rc.conf" \
+ --key "slapd_flags" \
+ --value "\"-h '${slapd_urls}'\"" \
+ --delimiter "=" \
+ --comment "# LDAP Listener URLs" \
+ "${__target_host}__slapd_flags"
+ ;;
+ debian|ubuntu|devuan)
+ require="__package/${PKG_MAIN}" __line rm_slapd_conf \
+ --file ${ETC}/default/slapd \
+ --regex 'SLAPD_CONF=.*' \
+ --state absent
+
+ require="__package/${PKG_MAIN}" __line rm_slapd_services \
+ --file ${ETC}/default/slapd \
+ --regex 'SLAPD_SERVICES=.*' \
+ --state absent
+
+ require="__line/rm_slapd_conf" __line add_slapd_conf \
+ --file ${ETC}/default/slapd \
+ --line "SLAPD_CONF=${SLAPD_DIR}/slapd.conf" \
+ --state present
+
+ require="__line/rm_slapd_services" __line add_slapd_services \
+ --file ${ETC}/default/slapd \
+ --line "SLAPD_SERVICES=\"${slapd_urls}\"" \
+ --state present
+ ;;
+ *)
+ # Nothing to do here, move on.
+ ;;
+esac
+
+
+if [ -z "${_skip_letsencrypt_cert}" ]; then
+ if [ -f "${__object}/parameter/staging" ]; then
+ staging="--staging"
+ else
+ staging=""
+ fi
+
+ # shellcheck disable=SC2086
+ __letsencrypt_cert "${name}" --admin-email "${admin_email}" \
+ --renew-hook "cp ${ETC}/letsencrypt/live/${name}/*.pem ${SLAPD_DIR}/sasl2 && chown -R openldap:openldap ${SLAPD_DIR}/sasl2 && service slapd restart" \
+ --automatic-renewal ${staging}
+fi
+
+require="__package/${PKG_MAIN}" __directory ${SLAPD_DIR}/slapd.d --state absent
+
+if [ -z "${_skip_letsencrypt_cert}" ]; then
+ require="__package/${PKG_MAIN} __letsencrypt_cert/${name}" \
+ __file ${SLAPD_DIR}/slapd.conf --owner ${CONF_OWNER} --group ${CONF_GROUP} --mode 644 \
+ --source "${ldapconf}"
+else
+ require="__package/${PKG_MAIN}" \
+ __file ${SLAPD_DIR}/slapd.conf --owner ${CONF_OWNER} --group ${CONF_GROUP} --mode 644 \
+ --source "${ldapconf}"
+fi
+
+# Start slapd.conf
+cat << EOF > "${ldapconf}"
+pidfile ${SLAPD_RUN_DIR}/slapd.pid
+argsfile ${SLAPD_RUN_DIR}/slapd.args
+
+TLSCipherSuite ${tls_cipher_suite}
+TLSCertificateFile ${tls_cert}
+TLSCertificateKeyFile ${tls_privkey}
+TLSCACertificateFile ${tls_ca}
+
+disallow bind_anon
+require bind
+security tls=1
+EOF
+
+# Add specified schemas
+for schema in ${schemas}; do
+ echo "include ${SLAPD_DIR}/schema/${schema}.schema" >> "${ldapconf}"
+done
+
+# Add specified modules
+echo "modulepath ${SLAPD_MODULE_PATH}" >> "${ldapconf}"
+for module in ${slapd_modules}; do
+ echo "moduleload ${module}.la" >> "${ldapconf}"
+done
+
+# Rest of the config
+cat << EOF >> "${ldapconf}"
+loglevel 1024
+
+database mdb
+maxsize 1073741824
+
+suffix "${suffix}"
+directory ${SLAPD_DATA_DIR}
+rootdn "${manager_dn}"
+rootpw "${manager_password_hash}"
+
+index objectClass eq,pres
+index ou,cn,mail,surname,givenname eq,pres,sub
+index uidNumber,gidNumber,loginShell eq,pres
+index uid,memberUid eq,pres,sub
+index nisMapName,nisMapEntry eq,pres,sub
+index entryCSN,entryUUID eq
+
+${extra_config}
+
+serverid ${serverid}
+EOF
+
+# Setup replication
+if [ "${replication}" ]; then
+ rid=1;
+ for syncrepl in ${syncrepl_hosts}; do
+ cat <> "${ldapconf}"
+syncrepl rid=${rid}
+ provider=ldap://${syncrepl}
+ bindmethod=simple
+ starttls=yes
+ binddn="${manager_dn}"
+ credentials=${syncrepl_credentials}
+ searchbase="${syncrepl_searchbase}"
+ type=refreshAndPersist
+ retry="5 + 5 +"
+ interval=00:00:00:05
+EOF
+ rid=$((rid + 1))
+ done
+ cat <> "${ldapconf}"
+mirrormode true
+overlay syncprov
+syncprov-checkpoint 100 5
+syncprov-sessionlog 100
+
+database monitor
+limits dn.exact="${manager_dn}" time=unlimited size=unlimited
+EOF
+fi
diff --git a/cdist/conf/type/__openldap_server/parameter/boolean b/cdist/conf/type/__openldap_server/parameter/boolean
new file mode 100644
index 00000000..45056fe9
--- /dev/null
+++ b/cdist/conf/type/__openldap_server/parameter/boolean
@@ -0,0 +1,2 @@
+staging
+replicate
diff --git a/cdist/conf/type/__openldap_server/parameter/default/description b/cdist/conf/type/__openldap_server/parameter/default/description
new file mode 100644
index 00000000..6d8e37e1
--- /dev/null
+++ b/cdist/conf/type/__openldap_server/parameter/default/description
@@ -0,0 +1 @@
+Managed by cdist, do not edit manually.
diff --git a/cdist/conf/type/__openldap_server/parameter/default/schema b/cdist/conf/type/__openldap_server/parameter/default/schema
new file mode 100644
index 00000000..825bdb15
--- /dev/null
+++ b/cdist/conf/type/__openldap_server/parameter/default/schema
@@ -0,0 +1,12 @@
+corba
+core
+cosine
+duaconf
+dyngroup
+inetorgperson
+java
+misc
+nis
+openldap
+ppolicy
+collective
diff --git a/cdist/conf/type/__openldap_server/parameter/optional b/cdist/conf/type/__openldap_server/parameter/optional
new file mode 100644
index 00000000..71c64659
--- /dev/null
+++ b/cdist/conf/type/__openldap_server/parameter/optional
@@ -0,0 +1,9 @@
+description
+syncrepl-credentials
+syncrepl-searchbase
+admin-email
+tls-cipher-suite
+tls-cert
+tls-privkey
+tls-ca
+extra-config
diff --git a/cdist/conf/type/__openldap_server/parameter/optional_multiple b/cdist/conf/type/__openldap_server/parameter/optional_multiple
new file mode 100644
index 00000000..52a83d5c
--- /dev/null
+++ b/cdist/conf/type/__openldap_server/parameter/optional_multiple
@@ -0,0 +1,3 @@
+syncrepl-host
+module
+schema
diff --git a/cdist/conf/type/__openldap_server/parameter/required b/cdist/conf/type/__openldap_server/parameter/required
new file mode 100644
index 00000000..ff58158d
--- /dev/null
+++ b/cdist/conf/type/__openldap_server/parameter/required
@@ -0,0 +1,5 @@
+manager-dn
+manager-password
+manager-password-hash
+serverid
+suffix
diff --git a/cdist/conf/type/__openldap_server/parameter/required_multiple b/cdist/conf/type/__openldap_server/parameter/required_multiple
new file mode 100644
index 00000000..848b8dc2
--- /dev/null
+++ b/cdist/conf/type/__openldap_server/parameter/required_multiple
@@ -0,0 +1 @@
+slapd-url
\ No newline at end of file
diff --git a/cdist/conf/type/__openldap_server/singleton b/cdist/conf/type/__openldap_server/singleton
new file mode 100644
index 00000000..e69de29b
diff --git a/cdist/conf/type/__package_apt/gencode-remote b/cdist/conf/type/__package_apt/gencode-remote
index 699eb0c9..e02564a2 100755
--- a/cdist/conf/type/__package_apt/gencode-remote
+++ b/cdist/conf/type/__package_apt/gencode-remote
@@ -74,6 +74,14 @@ fi
case "$state_should" in
present)
+ # following is bit ugly, but important hack.
+ # due to how cdist config run works, there isn't
+ # currently better way to do it :(
+ cat << EOF
+if [ ! -f /var/cache/apt/pkgcache.bin ] || [ "\$( stat --format %Y /var/cache/apt/pkgcache.bin )" -lt "\$( date +%s -d '-1 day' )" ]
+then echo apt-get update > /dev/null 2>&1 || true
+fi
+EOF
if [ -n "$version" ]; then
name="${name}=${version}"
fi
diff --git a/cdist/conf/type/__package_apt/man.rst b/cdist/conf/type/__package_apt/man.rst
index a3a70d91..a1691eac 100644
--- a/cdist/conf/type/__package_apt/man.rst
+++ b/cdist/conf/type/__package_apt/man.rst
@@ -11,6 +11,9 @@ DESCRIPTION
apt-get is usually used on Debian and variants (like Ubuntu) to
manage packages.
+This type will also update package index, if it is older
+than one day, to avoid missing package error messages.
+
REQUIRED PARAMETERS
-------------------
diff --git a/cdist/conf/type/__package_update_index/explorer/currage b/cdist/conf/type/__package_update_index/explorer/currage
index cfb778d5..8eadaf53 100644
--- a/cdist/conf/type/__package_update_index/explorer/currage
+++ b/cdist/conf/type/__package_update_index/explorer/currage
@@ -24,18 +24,18 @@ case "$type" in
if [ -f "/var/cache/apt/pkgcache.bin" ]; then
echo $(($(date +"%s")-$(stat --format '%Y' /var/cache/apt/pkgcache.bin)))
else
- echo 0
+ echo -- -1
fi
;;
pacman)
if [ -d "/var/lib/pacman/sync" ]; then
echo $(($(date +"%s")-$(stat --format '%Y' /var/lib/pacman/sync)))
else
- echo 0
+ echo -- -1
fi
;;
alpine)
- echo 0
+ echo -- -1
;;
*) echo "Your specified type ($type) is currently not supported." >&2
echo "Please contribute an implementation for it if you can." >&2
diff --git a/cdist/conf/type/__package_update_index/gencode-remote b/cdist/conf/type/__package_update_index/gencode-remote
index 9b2ecba2..803468b5 100755
--- a/cdist/conf/type/__package_update_index/gencode-remote
+++ b/cdist/conf/type/__package_update_index/gencode-remote
@@ -31,7 +31,8 @@ if [ -n "$maxage" ]; then
if [ "$type" != "apt" ] && [ "$type" != "pacman" ]; then
echo "ERROR: \"--maxage\" only supported for \"apt\" or \"pacman\" pkg-manager." >&2
exit 1
- elif [ "$currage" -lt "$maxage" ]; then
+ # do not exit if no value found (represented as -1)
+ elif [ "$currage" -ne -1 ] && [ "$currage" -lt "$maxage" ]; then
exit 0 # no need to update
fi
fi
@@ -47,9 +48,9 @@ case "$type" in
echo "pacman --noprogressbar --sync --refresh"
echo "pacman package database synced (age was: $currage)" >> "$__messages_out"
;;
- alpine)
+ apk)
echo "apk update"
- echo "apk package database updated."
+ echo "apk package database updated." >>"$__messages_out"
;;
*)
echo "Don't know how to manage packages for type: $type" >&2
diff --git a/cdist/conf/type/__pf_apply/deprecated b/cdist/conf/type/__pf_apply/deprecated
new file mode 100644
index 00000000..36cfed90
--- /dev/null
+++ b/cdist/conf/type/__pf_apply/deprecated
@@ -0,0 +1 @@
+Consider moving to __pf_apply_anchor. Get in touch if you need __pf_apply.
diff --git a/cdist/conf/type/__pf_ruleset/explorer/cksum b/cdist/conf/type/__pf_apply_anchor/gencode-remote
similarity index 55%
rename from cdist/conf/type/__pf_ruleset/explorer/cksum
rename to cdist/conf/type/__pf_apply_anchor/gencode-remote
index 9be6c901..36c26521 100755
--- a/cdist/conf/type/__pf_ruleset/explorer/cksum
+++ b/cdist/conf/type/__pf_apply_anchor/gencode-remote
@@ -1,6 +1,6 @@
-#!/bin/sh
+#!/bin/sh -e
#
-# 2012 Jake Guffey (jake.guffey at eprotex.com)
+# 2016 Kamila Součková (coding at kamila.is)
#
# This file is part of cdist.
#
@@ -18,24 +18,16 @@
# along with cdist. If not, see .
#
#
-# Get the 256 bit SHA2 checksum of the pf ruleset on the target host.
+# Apply pf(4) ruleset on *BSD
#
-# Debug
-#exec >&2
-#set -x
+ANCHORS_DIR="/etc/pf.d"
-# Check /etc/rc.conf for pf's configuration file name. Default to /etc/pf.conf
-# See if file exists and if so, get checksum
-
-RC="/etc/rc.conf"
-TMP="$(grep '^pf_rules=' ${RC} | cut -d= -f2 | sed 's/"//g')"
-PFCONF="${TMP:-"/etc/pf.conf"}"
-
-if [ -f "${PFCONF}" ]; then # The pf config file exists, find its cksum.
- cksum -o 1 "${PFCONF}" | cut -d= -f2 | awk '{print $1}'
+if [ -f "${__object}/parameter/anchor_name" ]; then
+ anchor_name="$(cat "${__object}/parameter/anchor_name")"
+else
+ anchor_name="${__object_id}"
fi
+anchor_file="${ANCHORS_DIR}/${anchor_name}"
-# Debug
-#set +x
-
+echo "pfctl -a \"${anchor_name}\" -f \"${anchor_file}\""
diff --git a/cdist/conf/type/__pf_apply_anchor/man.rst b/cdist/conf/type/__pf_apply_anchor/man.rst
new file mode 100644
index 00000000..aef6cdf4
--- /dev/null
+++ b/cdist/conf/type/__pf_apply_anchor/man.rst
@@ -0,0 +1,62 @@
+cdist-type__pf_apply_anchor(7)
+==============================
+
+NAME
+----
+cdist-type__pf_apply_anchor - Apply a pf(4) anchor on $__target_host
+
+
+DESCRIPTION
+-----------
+This type is used on \*BSD systems to manage anchors for the pf firewall.
+
+Notice this type does not take care of copying the ruleset, that must be
+done by the user with, e.g. `__file`.
+
+
+OPTIONAL PARAMETERS
+-------------------
+anchor_name
+ The name of the anchor to apply. If not set, `${__object_id}` is used.
+ This type requires `/etc/pf.d/${anchor_name}` to exist on
+ `$__target_host`.
+
+
+EXAMPLES
+--------
+
+.. code-block:: sh
+
+ # Copy anchor file to ${__target_host}
+ __file "/etc/pf.d/80_dns" --source - <
+Kamila Součková
+Jake Guffey
+
+
+COPYING
+-------
+Copyright \(C) 2020 Evilham.
+Copyright \(C) 2016 Kamila Součková.
+Copyright \(C) 2012 Jake Guffey. 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.
diff --git a/cdist/conf/type/__pf_apply_anchor/parameter/optional b/cdist/conf/type/__pf_apply_anchor/parameter/optional
new file mode 100644
index 00000000..b9f61e28
--- /dev/null
+++ b/cdist/conf/type/__pf_apply_anchor/parameter/optional
@@ -0,0 +1 @@
+anchor_name
diff --git a/cdist/conf/type/__pf_rdr/manifest b/cdist/conf/type/__pf_rdr/manifest
new file mode 100644
index 00000000..39ab4470
--- /dev/null
+++ b/cdist/conf/type/__pf_rdr/manifest
@@ -0,0 +1,40 @@
+#!/bin/sh -e
+#
+# 2016 Kamila Součková (coding at kamila.is)
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+
+# TODO it would be cool to print a warning if a generated anchor is unused in pf.conf
+
+ANCHORS_DIR=/etc/pf.d
+
+proto="$(cat "${__object}/parameter/proto")"
+from="$(cat "${__object}/parameter/from")"
+to="$(cat "${__object}/parameter/to")"
+state="$(cat "${__object}/parameter/state")"
+
+# This breaks utterly with IPv6
+from="$(echo ${from} | sed 's/:/ port /')"
+to="$(echo ${to} | sed 's/:/ port /')"
+
+anchor_name="$(echo ${__object_id} | cut -d/ -f1)"
+rule="rdr pass log proto ${proto} from any to ${from} -> ${to}"
+
+__directory "${ANCHORS_DIR}" --parents
+
+require="__directory/${ANCHORS_DIR}" \
+__line __pf_rdr/${__object_id} --state ${state} --line "${rule}" --file ${ANCHORS_DIR}/${anchor_name}
diff --git a/cdist/conf/type/__pf_rdr/parameter/default/proto b/cdist/conf/type/__pf_rdr/parameter/default/proto
new file mode 100644
index 00000000..28a29e6f
--- /dev/null
+++ b/cdist/conf/type/__pf_rdr/parameter/default/proto
@@ -0,0 +1 @@
+tcp
diff --git a/cdist/conf/type/__pf_rdr/parameter/default/state b/cdist/conf/type/__pf_rdr/parameter/default/state
new file mode 100644
index 00000000..e7f6134f
--- /dev/null
+++ b/cdist/conf/type/__pf_rdr/parameter/default/state
@@ -0,0 +1 @@
+present
diff --git a/cdist/conf/type/__pf_rdr/parameter/optional b/cdist/conf/type/__pf_rdr/parameter/optional
new file mode 100644
index 00000000..09ec92ca
--- /dev/null
+++ b/cdist/conf/type/__pf_rdr/parameter/optional
@@ -0,0 +1,2 @@
+proto
+state
diff --git a/cdist/conf/type/__pf_rdr/parameter/required b/cdist/conf/type/__pf_rdr/parameter/required
new file mode 100644
index 00000000..4a568482
--- /dev/null
+++ b/cdist/conf/type/__pf_rdr/parameter/required
@@ -0,0 +1,2 @@
+from
+to
diff --git a/cdist/conf/type/__pf_ruleset/gencode-local b/cdist/conf/type/__pf_ruleset/gencode-local
deleted file mode 100755
index 11bfb0b1..00000000
--- a/cdist/conf/type/__pf_ruleset/gencode-local
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/bin/sh -e
-#
-# 2012 Jake Guffey (jake.guffey at eprotex.com)
-#
-# This file is part of cdist.
-#
-# cdist 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.
-#
-# cdist 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 cdist. If not, see .
-#
-#
-# Manage pf(4) on *BSD
-#
-
-# Debug
-#exec >&2
-#set -x
-
-# Send files to $__target_host via $__remote_copy
-
-uname=$(uname) # Need to know what the cdist host is running so we know how to compute the ruleset's checksum
-state=$(cat "$__object/parameter/state")
-
-if [ "$state" = "absent" ]; then # There is nothing more for a *local* script to do
- exit 0
-fi
-
-if [ -f "$__object/parameter/source" ]; then
- source=$(cat "$__object/parameter/source")
-fi
-
-rcvar=$(cat "$__object/explorer/rcvar")
-cksum=$(cat "$__object/explorer/cksum")
-
-
-cat <&2
- exit 1
- ;;
-esac
-
-# IPv6 fix
-if $(echo "${__target_host}" | grep -q -E '^[0-9a-fA-F:]+$')
-then
- my_target_host="[${__target_host}]"
-else
- my_target_host="${__target_host}"
-fi
-
-if [ -n "${cksum}" ]; then
- if [ ! "\${currentSum}" = "${cksum}" ]; then
- $__remote_copy "${source}" "\${my_target_host}:${rcvar}.new"
- fi
-else # File just doesn't exist yet
- $__remote_copy "${source}" "\${my_target_host}:${rcvar}.new"
-fi
-EOF
-
-# Debug
-#exec +x
-
diff --git a/cdist/conf/type/__pf_ruleset/man.rst b/cdist/conf/type/__pf_ruleset/man.rst
index 5719e94e..db8873ac 100644
--- a/cdist/conf/type/__pf_ruleset/man.rst
+++ b/cdist/conf/type/__pf_ruleset/man.rst
@@ -10,6 +10,9 @@ DESCRIPTION
-----------
This type is used on \*BSD systems to manage the pf firewall's ruleset.
+It will also enable and disable the pf firewall as requested in the `state`
+parameter.
+
REQUIRED PARAMETERS
-------------------
@@ -20,9 +23,8 @@ state
OPTIONAL PARAMETERS
-------------------
source
- If supplied, use to define the ruleset to load onto the $__target_host for pf(4).
- Note that this type is almost useless without a ruleset defined, but it's technically not
- needed, e.g. for the case of disabling the firewall temporarily.
+ Required when state is "present".
+ Defines the ruleset to load onto the $__target_host for `pf(4)`.
EXAMPLES
@@ -30,10 +32,10 @@ EXAMPLES
.. code-block:: sh
- # Remove the current ruleset in place
+ # Remove the current ruleset in place and disable pf
__pf_ruleset --state absent
- # Enable the firewall with the ruleset defined in $__manifest/files/pf.conf
+ # Enable pf with the ruleset defined in $__manifest/files/pf.conf
__pf_ruleset --state present --source $__manifest/files/pf.conf
@@ -44,11 +46,13 @@ SEE ALSO
AUTHORS
-------
+Kamila Součková
Jake Guffey
COPYING
-------
+Copyright \(C) 2016 Kamila Součková.
Copyright \(C) 2012 Jake Guffey. 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
diff --git a/cdist/conf/type/__pf_ruleset/gencode-remote b/cdist/conf/type/__pf_ruleset/manifest
similarity index 51%
rename from cdist/conf/type/__pf_ruleset/gencode-remote
rename to cdist/conf/type/__pf_ruleset/manifest
index 12760fdf..27b35328 100755
--- a/cdist/conf/type/__pf_ruleset/gencode-remote
+++ b/cdist/conf/type/__pf_ruleset/manifest
@@ -1,6 +1,6 @@
#!/bin/sh -e
#
-# 2012 Jake Guffey (jake.guffey at eprotex.com)
+# 2016 Kamila Součková (coding at kamila.is)
#
# This file is part of cdist.
#
@@ -21,29 +21,26 @@
# Manage pf(4) on *BSD
#
-# Debug
-#exec >&2
-#set -x
-
-# Remove ${rcvar} in the case of --state absent
-
-state=$(cat "$__object/parameter/state")
-rcvar=$(cat "$__object/explorer/rcvar")
-
-if [ "$state" = "present" ]; then # There is nothing more for a *remote* script to do
- exit 0
-elif [ "$state" = "absent" ]; then
- # --state absent, so ensure that .new doesn't exist and that conf is renamed to .old
- cat <&2
- exit 1
+rcvar="$(cat "${__object}/explorer/rcvar")"
+state="$(cat "${__object}/parameter/state")"
+if [ -f "${__object}/parameter/source" ]; then
+ source="$(cat "${__object}/parameter/source")"
fi
+if [ "${state}" = "absent" ]; then
+ action="/etc/rc.d/pf stop"
+else
+ action="/etc/rc.d/pf reload || /etc/rc.d/pf start"
+fi
+
+__key_value __pf_ruleset/rcvar \
+ --state "${state}" \
+ --file /etc/rc.conf \
+ --delimiter "=" \
+ --key "pf_enable" \
+ --value "YES"
+
+require="__key_value/__pf_ruleset/rcvar" __config_file "${rcvar}" \
+ --source "${source}" \
+ --state "${state}" \
+ --onchange "${action}"
diff --git a/cdist/conf/type/__postfix/manifest b/cdist/conf/type/__postfix/manifest
index f3616979..121bba96 100755
--- a/cdist/conf/type/__postfix/manifest
+++ b/cdist/conf/type/__postfix/manifest
@@ -19,16 +19,4 @@
# along with cdist. If not, see .
#
-
-os=$(cat "$__global/explorer/os")
-
-case "$os" in
- alpine|ubuntu|debian|archlinux|suse|scientific|centos|devuan)
- __package postfix --state present
- ;;
- *)
- echo "Your operating system ($os) is currently not supported by this type (${__type##*/})." >&2
- echo "Please contribute an implementation for it if you can." >&2
- exit 1
- ;;
-esac
+__package postfix --state present
diff --git a/cdist/conf/type/__postgres_database/gencode-remote b/cdist/conf/type/__postgres_database/gencode-remote
index 61cfa50d..0f11cff4 100755
--- a/cdist/conf/type/__postgres_database/gencode-remote
+++ b/cdist/conf/type/__postgres_database/gencode-remote
@@ -41,12 +41,37 @@ if [ "$state_should" != "$state_is" ]; then
present)
owner=""
if [ -f "$__object/parameter/owner" ]; then
- owner="-O '$(cat "$__object/parameter/owner")'"
+ owner="-O \"$(cat "$__object/parameter/owner")\""
fi
- echo "su - '$postgres_user' -c \"createdb $owner '$name'\""
+
+ template=""
+ if [ -f "$__object/parameter/template" ]; then
+ template="--template \"$(cat "$__object/parameter/template")\""
+ fi
+
+ encoding=""
+ if [ -f "$__object/parameter/encoding" ]; then
+ encoding="--encoding \"$(cat "$__object/parameter/encoding")\""
+ fi
+
+ lc_collate=""
+ if [ -f "$__object/parameter/lc-collate" ]; then
+ lc_collate="--lc-collate \"$(cat "$__object/parameter/lc-collate")\""
+ fi
+
+ lc_ctype=""
+ if [ -f "$__object/parameter/lc-ctype" ]; then
+ lc_ctype="--lc-ctype \"$(cat "$__object/parameter/lc-ctype")\""
+ fi
+
+ cat << EOF
+su - '$postgres_user' -c "createdb $owner \"$name\" $template $encoding $lc_collate $lc_ctype"
+EOF
;;
absent)
- echo "su - '$postgres_user' -c \"dropdb '$name'\""
+ cat << EOF
+su - '$postgres_user' -c "dropdb \"$name\""
+EOF
;;
esac
fi
diff --git a/cdist/conf/type/__postgres_database/man.rst b/cdist/conf/type/__postgres_database/man.rst
index acceec9b..870b4917 100644
--- a/cdist/conf/type/__postgres_database/man.rst
+++ b/cdist/conf/type/__postgres_database/man.rst
@@ -14,10 +14,22 @@ This cdist type allows you to create or drop postgres databases.
OPTIONAL PARAMETERS
-------------------
state
- either 'present' or 'absent', defaults to 'present'.
+ Either 'present' or 'absent', defaults to 'present'.
owner
- the role owning this database
+ Specifies the database user who will own the new database.
+
+encoding
+ Specifies the character encoding scheme to be used in this database.
+
+lc-collate
+ Specifies the LC_COLLATE setting to be used in this database.
+
+lc-ctype
+ Specifies the LC_CTYPE setting to be used in this database.
+
+template
+ Specifies the template database from which to build this database.
EXAMPLES
diff --git a/cdist/conf/type/__postgres_database/parameter/optional b/cdist/conf/type/__postgres_database/parameter/optional
index d86b6469..877fbf32 100644
--- a/cdist/conf/type/__postgres_database/parameter/optional
+++ b/cdist/conf/type/__postgres_database/parameter/optional
@@ -1,2 +1,6 @@
state
owner
+encoding
+lc-collate
+lc-ctype
+template
diff --git a/cdist/conf/type/__postgres_role/gencode-remote b/cdist/conf/type/__postgres_role/gencode-remote
index fd56e85d..282294c9 100755
--- a/cdist/conf/type/__postgres_role/gencode-remote
+++ b/cdist/conf/type/__postgres_role/gencode-remote
@@ -53,11 +53,13 @@ case "$state_should" in
done
[ -n "$password" ] && password="PASSWORD '$password'"
-
- cmd="CREATE ROLE $name WITH $password $booleans"
- echo "su - '$postgres_user' -c \"psql postgres -wc \\\"$cmd\\\"\""
+ cat << EOF
+su - '$postgres_user' -c "psql postgres -wc \"CREATE ROLE \\\\\"$name\\\\\" WITH $password $booleans;\""
+EOF
;;
absent)
- echo "su - '$postgres_user' -c \"dropuser \\\"$name\\\"\""
+ cat << EOF
+su - '$postgres_user' -c "dropuser \"$name\""
+EOF
;;
esac
diff --git a/cdist/conf/type/__pyvenv/gencode-remote b/cdist/conf/type/__pyvenv/gencode-remote
index 04700683..9c7b7fab 100755
--- a/cdist/conf/type/__pyvenv/gencode-remote
+++ b/cdist/conf/type/__pyvenv/gencode-remote
@@ -37,11 +37,21 @@ mode="$(cat "$__object/parameter/mode")"
destination="/$__object_id"
venvparams="$(cat "$__object/parameter/venvparams")"
pyvenvparam="$__object/parameter/pyvenv"
+
+os=$(cat "$__global/explorer/os")
+
if [ -f "$pyvenvparam" ]
then
pyvenv=$(cat "$pyvenvparam")
else
- pyvenv="pyvenv"
+ case "$os" in
+ alpine) # no pyvenv on alpine - I assume others will follow
+ pyvenv="python3 -m venv"
+ ;;
+ *)
+ pyvenv="pyvenv"
+ ;;
+ esac
fi
case $state_should in
diff --git a/cdist/conf/type/__service/explorer/service-manager b/cdist/conf/type/__service/explorer/service-manager
new file mode 100755
index 00000000..55a873fa
--- /dev/null
+++ b/cdist/conf/type/__service/explorer/service-manager
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# Assume systemd if systemctl is in PATH.
+if [ "$(command -v systemctl)" ]; then
+ printf "systemd"
+else
+ printf "unknown"
+fi
diff --git a/cdist/conf/type/__service/gencode-remote b/cdist/conf/type/__service/gencode-remote
new file mode 100755
index 00000000..ac62e05f
--- /dev/null
+++ b/cdist/conf/type/__service/gencode-remote
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+manager="$(cat "$__object/explorer/service-manager")"
+name=$__object_id
+action="$(cat "$__object/parameter/action")"
+
+if [ "$manager" = "unknown" ]; then
+ echo "service '$name' '$action'"
+fi
diff --git a/cdist/conf/type/__service/man.rst b/cdist/conf/type/__service/man.rst
new file mode 100644
index 00000000..f9b23d5b
--- /dev/null
+++ b/cdist/conf/type/__service/man.rst
@@ -0,0 +1,51 @@
+cdist-type__service(7)
+======================
+
+NAME
+----
+cdist-type__service - Run action on a system service
+
+
+DESCRIPTION
+-----------
+This type allows you to run an action against a system service.
+
+
+REQUIRED PARAMETERS
+-------------------
+action
+ Arbitrary parameter passed as action. Usually 'start', 'stop', 'reload' or 'restart'.
+
+OPTIONAL PARAMETERS
+-------------------
+None.
+
+
+BOOLEAN PARAMETERS
+------------------
+None.
+
+
+EXAMPLES
+--------
+
+.. code-block:: sh
+
+ # Restart nginx service.
+ __service nginx --action restart
+
+ # Stop postfix service.
+ __service postfix --action stop
+
+
+AUTHORS
+-------
+Timothée Floure
+
+
+COPYING
+-------
+Copyright \(C) 2019 Timothée Floure. 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.
diff --git a/cdist/conf/type/__service/manifest b/cdist/conf/type/__service/manifest
new file mode 100644
index 00000000..cb5af234
--- /dev/null
+++ b/cdist/conf/type/__service/manifest
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+manager="$(cat "$__object/explorer/service-manager")"
+
+name=$__object_id
+action="$(cat "$__object/parameter/action")"
+
+case "$manager" in
+ systemd)
+ __systemd_service "$name" --action "$action"
+ ;;
+ *)
+ # Unknown: handled by `service $NAME $action` in gencode-remote.
+ ;;
+esac
diff --git a/cdist/conf/type/__service/parameter/required b/cdist/conf/type/__service/parameter/required
new file mode 100644
index 00000000..a9f84d41
--- /dev/null
+++ b/cdist/conf/type/__service/parameter/required
@@ -0,0 +1 @@
+action
diff --git a/cdist/conf/type/__start_on_boot/man.rst b/cdist/conf/type/__start_on_boot/man.rst
index b7c73ab1..f8afe94b 100644
--- a/cdist/conf/type/__start_on_boot/man.rst
+++ b/cdist/conf/type/__start_on_boot/man.rst
@@ -12,7 +12,7 @@ This cdist type allows you to enable or disable stuff to be started
at boot of your operating system.
Warning: This type has not been tested intensively and is not fully
-supported (i.e. \*BSD are not implemented).
+supported.
REQUIRED PARAMETERS
diff --git a/cdist/conf/type/__systemd_service/explorer/state b/cdist/conf/type/__systemd_service/explorer/state
new file mode 100755
index 00000000..f5f751d4
--- /dev/null
+++ b/cdist/conf/type/__systemd_service/explorer/state
@@ -0,0 +1,43 @@
+#!/bin/sh -e
+# explorer/state
+#
+# 2020 Matthias Stecher
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+
+# Check if the service is running or stopped.
+#
+# The explorer must check before if the service exist, because 'systemctl is-active'
+# will return "inactive" even if there is no service there:
+# systemctl cat foo # does not exist
+# systemctl is-active foo # is "inactive"
+
+
+# get name of the service
+if [ -f "$__object/parameter/name" ]; then
+ name="$(cat "$__object/parameter/name")"
+else
+ name="$__object_id"
+fi
+
+
+# check if the service exist, else exit without output (also if systemd doesn't exist)
+# do not exit here with an error code, will be done in the gencode-remote script
+systemctl cat "$name" > /dev/null 2>&1 || exit 0
+
+# print if the service is running or not
+systemctl is-active -q "$name" && printf "running" || printf "stopped"
diff --git a/cdist/conf/type/__systemd_service/gencode-remote b/cdist/conf/type/__systemd_service/gencode-remote
new file mode 100755
index 00000000..c867ff22
--- /dev/null
+++ b/cdist/conf/type/__systemd_service/gencode-remote
@@ -0,0 +1,98 @@
+#!/bin/sh -e
+# gencode-remote
+#
+# 2020 Matthias Stecher
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+
+# Checks the given state of the service and set it to the given
+# state. Optionally, it executes the action if service running.
+
+
+# get name of the service
+name="$__object/parameter/name"
+if [ -f "$name" ]; then
+ name="$(cat "$name")"
+else
+ name="$__object_id"
+fi
+
+
+# read current status and parameters
+state="$(cat "$__object/explorer/state")"
+should="$(cat "$__object/parameter/state")"
+
+# if systemd/service does not exist
+if [ -z "$state" ]; then
+ printf "systemd or service '%s' does not exist!\n" "$name" >&2
+ exit 1
+fi
+
+
+# save the action required
+required_action=""
+
+# check the state of the service that should be
+if [ "$state" != "$should" ]; then
+ # select what to do to get the $should state
+ case "$should" in
+ running)
+ if [ "$state" = "stopped" ]; then required_action="start"; fi
+ ;;
+
+ stopped)
+ if [ "$state" = "running" ]; then required_action="stop"; fi
+ ;;
+ esac
+fi
+
+# check if the action can be achieved if given
+if [ -f "$__object/parameter/action" ] \
+ && [ -z "$required_action" ] && [ "$state" = "running" ]; then
+
+ # there must be an action
+ action="$(cat "$__object/parameter/action")"
+
+ # select the action to the required element
+ case "$action" in
+ restart)
+ required_action="restart"
+ ;;
+
+ reload)
+ required_action="reload"
+ ;;
+
+ *)
+ printf "action '%s' does not exist!" "$action" >&2
+ exit 2
+ esac
+
+ # Make a special check: only do this action if a dependency did something
+ # it is required that the dependencies write there action to $__messages_in
+ if [ -f "$__object/parameter/if-required" ]; then
+ # exit here if there are no changes from the dependencies affected (nothing to do)
+ if ! grep -q -f "$__object/require" "$__messages_in"; then exit 0; fi
+ fi
+fi
+
+# print the execution command if a action given
+if [ -n "$required_action" ]; then
+ # also print it as message
+ echo "$required_action" >> "$__messages_out"
+ echo "systemctl $required_action '$name'"
+fi
diff --git a/cdist/conf/type/__systemd_service/man.rst b/cdist/conf/type/__systemd_service/man.rst
new file mode 100644
index 00000000..7eca398b
--- /dev/null
+++ b/cdist/conf/type/__systemd_service/man.rst
@@ -0,0 +1,110 @@
+cdist-type__systemd-service(7)
+==============================
+
+NAME
+----
+cdist-type__systemd-service - Controls a systemd service state
+
+DESCRIPTION
+-----------
+This type controls systemd services to define a state of the service,
+or an action like reloading or restarting. It is useful to reload a
+service after configuration applied or shutdown one service.
+
+The activation or deactivation is out of scope. Look for the
+:strong:`cdist-type__systemd_util`\ (7) type instead.
+
+REQUIRED PARAMETERS
+-------------------
+
+None.
+
+OPTIONAL PARAMETERS
+-------------------
+
+name
+ String which will used as name instead of the object id.
+
+state
+ The state which the service should be in:
+
+ running
+ Service should run (default)
+
+ stoppend
+ Service should stopped
+
+action
+ Executes an action on on the service. It will only execute it if the
+ service keeps the state **running**. There are following actions, where:
+
+ reload
+ Reloads the service
+
+ restart
+ Restarts the service
+
+BOOLEAN PARAMETERS
+------------------
+
+if-required
+ Only execute the action if minimum one required type outputs a message to
+ **$__messages_out**. Through this, the action should only executed if a
+ dependency did something. The action will not executed if no dependencies
+ given.
+
+MESSAGES
+--------
+
+start
+ Started the service
+
+stop
+ Stopped the service
+
+restart
+ Restarted the service
+
+reload
+ Reloaded the service
+
+ABORTS
+------
+Aborts in following cases:
+
+systemd or the service does not exist
+
+EXAMPLES
+--------
+.. code-block:: sh
+
+ # service must run
+ __systemd_service nginx
+
+ # service must stopped
+ __systemd_service sshd \
+ --state stopped
+
+ # restart the service
+ __systemd_service apache2 \
+ --action restart
+
+ # makes sure the service exist with an alternative name
+ __systemd_service foo \
+ --name sshd
+
+ # reload the service for a modified configuration file
+ # only reloads the service if the file really changed
+ require="__config_file/etc/foo.conf" __systemd_service foo \
+ --action reload --if-required
+
+AUTHORS
+-------
+Matthias Stecher
+
+COPYRIGHT
+---------
+Copyright \(C) 2020 Matthias Stecher. 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.
diff --git a/cdist/conf/type/__systemd_service/parameter/boolean b/cdist/conf/type/__systemd_service/parameter/boolean
new file mode 100644
index 00000000..a4bccb66
--- /dev/null
+++ b/cdist/conf/type/__systemd_service/parameter/boolean
@@ -0,0 +1 @@
+if-required
diff --git a/cdist/conf/type/__systemd_service/parameter/default/state b/cdist/conf/type/__systemd_service/parameter/default/state
new file mode 100644
index 00000000..a2ae71b3
--- /dev/null
+++ b/cdist/conf/type/__systemd_service/parameter/default/state
@@ -0,0 +1 @@
+running
diff --git a/cdist/conf/type/__systemd_service/parameter/optional b/cdist/conf/type/__systemd_service/parameter/optional
new file mode 100644
index 00000000..fc78265f
--- /dev/null
+++ b/cdist/conf/type/__systemd_service/parameter/optional
@@ -0,0 +1,3 @@
+name
+state
+action
diff --git a/cdist/conf/type/__tinydns/gencode-remote b/cdist/conf/type/__tinydns/gencode-remote
new file mode 100644
index 00000000..824479b6
--- /dev/null
+++ b/cdist/conf/type/__tinydns/gencode-remote
@@ -0,0 +1,7 @@
+servicename=$__object_id
+user="$(cat "$__object/parameter/user")"
+server_ip="$(cat "$__object/parameter/server-ip")"
+
+cat</dev/null || ./add-host $name $ip
+make
+EOF
diff --git a/cdist/conf/type/__tinydns_host/manifest b/cdist/conf/type/__tinydns_host/manifest
new file mode 100644
index 00000000..e69de29b
diff --git a/cdist/conf/type/__tinydns_host/parameter/required b/cdist/conf/type/__tinydns_host/parameter/required
new file mode 100644
index 00000000..93d111b2
--- /dev/null
+++ b/cdist/conf/type/__tinydns_host/parameter/required
@@ -0,0 +1 @@
+ip
diff --git a/cdist/conf/type/__tinydns_ns/gencode-remote b/cdist/conf/type/__tinydns_ns/gencode-remote
new file mode 100644
index 00000000..7305e605
--- /dev/null
+++ b/cdist/conf/type/__tinydns_ns/gencode-remote
@@ -0,0 +1,13 @@
+set -x
+
+servicename=$(echo $__object_id | cut -d/ -f1)
+name=$(echo $__object_id | cut -d/ -f2-)
+ip="$(cat "$__object/parameter/ip")"
+
+cat</dev/null || ./add-ns $name $ip
+make
+EOF
+
+set +x
diff --git a/cdist/conf/type/__tinydns_ns/parameter/required b/cdist/conf/type/__tinydns_ns/parameter/required
new file mode 100644
index 00000000..93d111b2
--- /dev/null
+++ b/cdist/conf/type/__tinydns_ns/parameter/required
@@ -0,0 +1 @@
+ip
diff --git a/cdist/conf/type/__update_alternatives/explorer/state b/cdist/conf/type/__update_alternatives/explorer/state
new file mode 100755
index 00000000..04a78aaa
--- /dev/null
+++ b/cdist/conf/type/__update_alternatives/explorer/state
@@ -0,0 +1,8 @@
+#!/bin/sh -e
+path="$(cat "$__object/parameter/path")"
+name="$__object_id"
+link="$(readlink "/etc/alternatives/$name")"
+if [ "$path" = "$link" ]
+then echo present
+else echo absent
+fi
diff --git a/cdist/conf/type/__update_alternatives/gencode-remote b/cdist/conf/type/__update_alternatives/gencode-remote
index 0e7b0d89..c0b49814 100755
--- a/cdist/conf/type/__update_alternatives/gencode-remote
+++ b/cdist/conf/type/__update_alternatives/gencode-remote
@@ -17,9 +17,10 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see .
#
-#
-# Setup alternative - no standard way to create, always set
-#
+
+if [ "$(cat "$__object/explorer/state")" = 'present' ]
+then exit 0
+fi
path="$(cat "$__object/parameter/path")"
name="$__object_id"
diff --git a/cdist/conf/type/__user/explorer/shadow b/cdist/conf/type/__user/explorer/shadow
index 73ce0e29..63d38f0d 100755
--- a/cdist/conf/type/__user/explorer/shadow
+++ b/cdist/conf/type/__user/explorer/shadow
@@ -24,7 +24,7 @@
name=$__object_id
case $("$__explorer/os") in
- 'freebsd'|'netbsd'|'openbsd')
+ 'freebsd'|'netbsd'|'openbsd'|'alpine')
database='passwd'
;;
# Default to using shadow passwords
diff --git a/cdist/configuration.py b/cdist/configuration.py
index f05a5963..1011a382 100644
--- a/cdist/configuration.py
+++ b/cdist/configuration.py
@@ -274,7 +274,8 @@ class Configuration(metaclass=Singleton):
os.path.isfile(_local_config_file))):
_local_config_file = os.path.join(
os.environ.get('XDG_CONFIG_HOME',
- os.path.expanduser('~/.config/cdist')),
+ os.path.expanduser('~/.config/')),
+ 'cdist',
_config_basename)
_dist_config_file = os.path.join(
os.path.abspath(os.path.join(os.path.dirname(cdist.__file__), "conf")),
diff --git a/cdist/exec/local.py b/cdist/exec/local.py
index f83c85df..ad6c6e36 100644
--- a/cdist/exec/local.py
+++ b/cdist/exec/local.py
@@ -69,7 +69,6 @@ class Local(object):
self.exec_path = exec_path
self.custom_initial_manifest = initial_manifest
- self._add_conf_dirs = add_conf_dirs
self.cache_path_pattern = cache_path_pattern
self.quiet_mode = quiet_mode
if configuration:
@@ -84,16 +83,7 @@ class Local(object):
self._init_cache_dir(None)
self._init_paths()
self._init_object_marker()
- self._init_conf_dirs()
-
- @property
- def dist_conf_dir(self):
- return os.path.abspath(os.path.join(os.path.dirname(cdist.__file__),
- "conf"))
-
- @property
- def home_dir(self):
- return cdist.home_dir()
+ self._init_conf_dirs(add_conf_dirs)
def _init_log(self):
self.log = logging.getLogger(self.target_host[0])
@@ -140,28 +130,9 @@ class Local(object):
# Does not need to be secure - just randomly different from .cdist
self.object_marker_name = tempfile.mktemp(prefix='.cdist-', dir='')
- def _init_conf_dirs(self):
- self.conf_dirs = []
-
- self.conf_dirs.append(self.dist_conf_dir)
-
- # Is the default place for user created explorer, type and manifest
- if self.home_dir:
- self.conf_dirs.append(self.home_dir)
-
- # Add directories defined in the CDIST_PATH environment variable
- # if 'CDIST_PATH' in os.environ:
- # cdist_path_dirs = re.split(r'(?.
+#
+#
+
+import cdist
+import cdist.configuration
+import cdist.core
+import cdist.exec.util as util
+import os
+import glob
+import fnmatch
+
+
+class Info(object):
+
+ def __init__(self, conf_dirs, args):
+ self.conf_dirs = conf_dirs
+ self.all = args.all
+ self.display_global_explorers = args.global_explorers
+ self.display_types = args.types
+ if not self.display_global_explorers and not self.display_types:
+ self.all = True
+ self.fixed_string = args.fixed_string
+ self._setup_glob_pattern(args.pattern)
+ self.full = args.full
+
+ def _setup_glob_pattern(self, pattern):
+ if pattern is None:
+ self.glob_pattern = '*'
+ elif ('?' in pattern or '*' in pattern or '[' in pattern or
+ self.fixed_string):
+ self.glob_pattern = pattern
+ else:
+ self.glob_pattern = '*' + pattern + '*'
+
+ @classmethod
+ def commandline(cls, args):
+ conf_dirs = util.resolve_conf_dirs_from_config_and_args(args)
+ c = cls(conf_dirs, args)
+ c.run()
+
+ def _get_global_explorers(self, conf_path):
+ rv = []
+ global_explorer_path = os.path.join(conf_path, "explorer",
+ self.glob_pattern)
+ if self.fixed_string:
+ if os.path.exists(global_explorer_path):
+ rv.append(global_explorer_path)
+ else:
+ for explorer in glob.glob(global_explorer_path):
+ rv.append(explorer)
+ return rv
+
+ def _should_display_type(self, dir_entry):
+ if not dir_entry.is_dir():
+ return False
+ if self.glob_pattern is None:
+ return True
+ if self.fixed_string:
+ return dir_entry.name == self.glob_pattern
+ else:
+ return fnmatch.fnmatch(dir_entry.name, self.glob_pattern)
+
+ def _get_types(self, conf_path):
+ rv = []
+ types_path = os.path.join(conf_path, "type")
+ if not os.path.exists(types_path):
+ return rv
+ with os.scandir(types_path) as it:
+ for entry in it:
+ if self._should_display_type(entry):
+ rv.append(entry.path)
+ return rv
+
+ def _display_details(self, title, details, default_values=None,
+ deprecated=None):
+ if not details:
+ return
+ if isinstance(details, bool):
+ print("\t{}: {}".format(title, 'yes' if details else 'no'))
+ elif isinstance(details, str):
+ print("\t{}: {}".format(title, details))
+ elif isinstance(details, list):
+ dv = dict(default_values) if default_values else {}
+ dp = dict(deprecated) if deprecated else {}
+
+ print("\t{}:".format(title))
+ for x in sorted(details):
+ print("\t\t{}".format(x), end='')
+ has_default = x in dv
+ is_deprecated = x in dp
+ need_comma = False
+ if has_default or is_deprecated:
+ print(" (", end='')
+ if has_default:
+ print("default: {}".format(dv[x]), end='')
+ need_comma = True
+ if is_deprecated:
+ print("{}deprecated".format(', ' if need_comma else ''),
+ end='')
+ if has_default or is_deprecated:
+ print(")", end='')
+ print()
+
+ def _display_type_parameters(self, cdist_type):
+ self._display_details("required parameters",
+ cdist_type.required_parameters,
+ default_values=cdist_type.parameter_defaults,
+ deprecated=cdist_type.deprecated_parameters)
+ self._display_details("required multiple parameters",
+ cdist_type.required_multiple_parameters,
+ default_values=cdist_type.parameter_defaults,
+ deprecated=cdist_type.deprecated_parameters)
+ self._display_details("optional parameters",
+ cdist_type.optional_parameters,
+ default_values=cdist_type.parameter_defaults,
+ deprecated=cdist_type.deprecated_parameters)
+ self._display_details("optional multiple parameters",
+ cdist_type.optional_multiple_parameters,
+ default_values=cdist_type.parameter_defaults,
+ deprecated=cdist_type.deprecated_parameters)
+ self._display_details("boolean parameters",
+ cdist_type.boolean_parameters,
+ default_values=cdist_type.parameter_defaults,
+ deprecated=cdist_type.deprecated_parameters)
+
+ def _display_type_characteristics(self, cdist_type):
+ characteristics = []
+ if cdist_type.is_install:
+ characteristics.append('install')
+ else:
+ characteristics.append('config')
+ if cdist_type.is_singleton:
+ characteristics.append('singleton')
+ if cdist_type.is_nonparallel:
+ characteristics.append('nonparallel')
+ else:
+ characteristics.append('parallel')
+ if cdist_type.deprecated is not None:
+ characteristics.append('deprecated')
+ print("\t{}".format(', '.join(characteristics)))
+
+ def _display_type_details(self, type_path):
+ dirname, basename = os.path.split(type_path)
+ cdist_type = cdist.core.CdistType(dirname, basename)
+
+ self._display_type_characteristics(cdist_type)
+ self._display_type_parameters(cdist_type)
+
+ def run(self):
+ rv = []
+ for cp in self.conf_dirs:
+ conf_path = os.path.expanduser(cp)
+ if self.all or self.display_global_explorers:
+ rv.extend((x, 'E', ) for x in self._get_global_explorers(
+ conf_path))
+ if self.all or self.display_types:
+ rv.extend((x, 'T', ) for x in self._get_types(conf_path))
+ rv = sorted(rv, key=lambda x: x[0])
+ for x, t in rv:
+ print(x)
+ if self.full and t == 'T':
+ self._display_type_details(x)
diff --git a/cdist/preos.py b/cdist/preos.py
index 46b45554..bf2a8e60 100644
--- a/cdist/preos.py
+++ b/cdist/preos.py
@@ -5,6 +5,9 @@ import inspect
import argparse
import cdist
import logging
+import cdist.argparse
+import cdist.configuration
+import cdist.exec.util as util
_PREOS_CALL = "commandline"
@@ -12,17 +15,16 @@ _PREOS_NAME = "_preos_name"
_PREOS_MARKER = "_cdist_preos"
_PLUGINS_DIR = "preos"
_PLUGINS_PATH = [os.path.join(os.path.dirname(__file__), _PLUGINS_DIR), ]
-cdist_home = cdist.home_dir()
-if cdist_home:
- cdist_home_preos = os.path.join(cdist_home, "preos")
- if os.path.isdir(cdist_home_preos):
- _PLUGINS_PATH.append(cdist_home_preos)
-sys.path.extend(_PLUGINS_PATH)
-
-
log = logging.getLogger("PreOS")
+def extend_plugins_path(dirs):
+ for dir in dirs:
+ preos_dir = os.path.expanduser(os.path.join(dir, "preos"))
+ if os.path.isdir(preos_dir):
+ _PLUGINS_PATH.append(preos_dir)
+
+
def preos_plugin(obj):
"""It is preos if _PREOS_MARKER is True and has _PREOS_CALL."""
if hasattr(obj, _PREOS_MARKER):
@@ -71,31 +73,58 @@ def check_root():
raise cdist.Error("Must be run with root privileges")
+def get_available_preoses_string(cls):
+ preoses = [' - {}'.format(x) for x in sorted(set(cls.preoses))]
+ return "Available PreOS-es:\n{}".format("\n".join(preoses))
+
+
class PreOS(object):
preoses = None
@classmethod
def commandline(cls, argv):
-
- if not cls.preoses:
- cls.preoses = find_preoses()
-
+ cdist_parser = cdist.argparse.get_parsers()
parser = argparse.ArgumentParser(
- description="Create PreOS", prog="cdist preos")
- parser.add_argument('preos', help='PreOS to create, one of: {}'.format(
- set(cls.preoses)))
- args = parser.parse_args(argv[1:2])
+ description="Create PreOS", prog="cdist preos",
+ parents=[cdist_parser['loglevel'], ])
+ parser.add_argument('preos', help='PreOS to create',
+ nargs='?', default=None)
+ parser.add_argument('-c', '--conf-dir',
+ help=('Add configuration directory (one that '
+ 'contains "preos" subdirectory)'),
+ action='append')
+ parser.add_argument('-g', '--config-file',
+ help='Use specified custom configuration file.',
+ dest="config_file", required=False)
+ parser.add_argument('-L', '--list-preoses',
+ help='List available PreOS-es',
+ action='store_true', default=False)
+ parser.add_argument('remainder_args', nargs=argparse.REMAINDER)
+ args = parser.parse_args(argv[1:])
+ cdist.argparse.handle_loglevel(args)
+ log.debug("preos args : {}".format(args))
+
+ conf_dirs = util.resolve_conf_dirs_from_config_and_args(args)
+
+ extend_plugins_path(conf_dirs)
+ sys.path.extend(_PLUGINS_PATH)
+ cls.preoses = find_preoses()
+
+ if args.list_preoses or not args.preos:
+ print(get_available_preoses_string(cls))
+ sys.exit(0)
preos_name = args.preos
if preos_name in cls.preoses:
preos = cls.preoses[preos_name]
func = getattr(preos, _PREOS_CALL)
if inspect.ismodule(preos):
- func_args = [preos, argv[2:], ]
+ func_args = [preos, args.remainder_args, ]
else:
- func_args = [argv[2:], ]
+ func_args = [args.remainder_args, ]
log.info("Running preos : {}".format(preos_name))
func(*func_args)
else:
- log.error("Unknown preos: {}, available preoses: {}".format(
- preos_name, set(cls.preoses.keys())))
+ raise cdist.Error(
+ "Invalid PreOS {}. {}".format(
+ preos_name, get_available_preoses_string(cls)))
diff --git a/docs/changelog b/docs/changelog
index 09e30e79..7cacf3cf 100644
--- a/docs/changelog
+++ b/docs/changelog
@@ -1,6 +1,81 @@
Changelog
---------
+next:
+ * Core: Fix XDG_CONFIG_HOME config file location (Joachim Desroches)
+ * Type __postgres_database: Add encoding, lc-collate, lc-ctype, template parameters (Timothée Floure)
+ * Type __motd: Improve documentation and support for FreeBSD (Evil Ham)
+ * Type __openldap_server: Support extra config parameter (Evil Ham)
+ * Type __postfix: Automagically support more OSs by not checking too much (Evil Ham)
+ * New type: __pf_apply_anchor (Kamila Součková, Evil Ham)
+ * Type __pf_ruleset: Refactor (Kamila Součková, Evil Ham)
+ * Type __pf_apply: Deprecate type (Kamila Součková, Evil Ham)
+
+6.5.4: 2020-04-11
+ * Explorer init: Do not grep on non-existent init (Steven Armstrong)
+ * Core: Bugfix to preserve conf dirs order (Steven Armstrong)
+
+6.5.3: 2020-04-03
+ * Type __cron: Make non parallel due to race condition (Nico Schottelius)
+ * Type __pyvenv: Use python3 -m venv on Alpine (Nico Schottelius)
+ * Type __user: Fix missing shadow for alpine (llnu)
+ * Type __consule_agent: Make conf_dir dependent on OS - fixes Alpine (Nico Schottelius)
+ * Type __letsencrypt_cert: Fix typo (Andrew Schleifer)
+ * Type __package_update_index: Fix maxage false positives (Matthias Stecher)
+
+6.5.2: 2020-02-27
+ * Type __update_alternatives: Add state explorer (Ander Punnar)
+ * Explorer os_version: Add support for Alpine Linux (Jin-Guk Kwon)
+ * Explorer init: Rewrite and support more init systems (Dennis Camera)
+ * New type: __service (Timothée Floure)
+ * Types __consul_*: Add optional parameter for using distribution packages (Timothée Floure)
+ * Explorer disks: Fix NetBSD, support Linux w/o lsblk (Dennis Camera)
+ * Type __directory: Add 'exists' and 'pre-exists' states (Dennis Camera)
+ * Type __file: Improve error messages for pre-exists state (Dennis Camera)
+
+6.5.1: 2020-02-15
+ * Type __consul_agent: Add Debian 10 support (Nico Schottelius)
+ * Explorer os_release: Add fallbacks (Dennis Camera)
+ * Types __file, __directory: Add fallback for systems without stat (Dennis Camera)
+ * Type __mysql_privileges: Fix quoting (Ander Punnar)
+ * Type __package_apt: Update package index if it is older than one day (Ander Punnar)
+ * Type __cron: Fix job removal if 'is' and 'should' don't match (Matthias Stecher)
+ * New type: __systemd_service (Matthias Stecher)
+ * Type __postgres_role: Fix password command syntax (Timothée Floure)
+
+6.5.0: 2020-01-23
+ * Type __acl: Add --entry parameter to replace --acl, deprecate --acl (Ander Punnar)
+ * Core: preos: Fix missing configuration file usage, support -g, --config-file option (Darko Poljak)
+ * Core info command: Support tilde expansion of conf directories (Darko Poljak)
+ * Types __postgres_*: Fix edge cases in quoted identifiers (Timothée Floure)
+ * New type: __apt_unattended_upgrades (Ander Punnar)
+ * Type __line: Bugfixes: (Dennis Camera)
+ - ensure the line is only added once
+ - always add line to end if anchor is not found
+ - match line at the beginning when not regex
+ - fix incorrect 'wrongposition' in state explorer
+ - produce error when file does not exist
+ * Type __acl: Add --source, --file and --directory parameters (Ander Punnar)
+
+6.4.0: 2020-01-04
+ * Type __consul_agent: Don't deploy init script on Alpine anymore, it ships with one itself (Nico Schottelius)
+ * Type __install_chroot_umount: Bugfix: type was not using __chroot_umount/manifest (Steven Armstrong)
+ * Types __postgres_*: Use double quoted identifiers in generated SQL (Timothée Floure)
+ * Core: Add cdist info command (Darko Poljak)
+ * New types: __mysql_user, __mysql_privileges (Ander Punnar)
+ * Type __mysql_database: Rewrite (Ander Punnar)
+
+6.3.0: 2019-12-12
+ * Type __package_update_index: Fix Alpine part (Dominique Roux)
+ * Documentation: Fix man pages for install types (Darko Poljak)
+ * Documentation: Embed config skeleton instead of rewriting it (Darko Poljak)
+ * Documentation: Remove cdist-type prefix and man page reference from type list in html (Darko Poljak)
+ * Documentation: PreOS english nitpicking (Evil Ham)
+ * Documentation: Add installing from source with signature verification (Darko Poljak)
+ * Core: preos: Support top command logging options, custom conf-dir option and CDIST_PATH env var (Darko Poljak)
+ * Type __start_on_boot: Docs: remove unsupported *BSD claim (Evil Ham)
+ * New type: __openldap_server (Evil Ham)
+
6.2.0: 2019-11-30
* Core: Redefine/reimplement/fix CDIST_ORDER_DEPENDENCY (Darko Poljak)
diff --git a/docs/src/cdist-configuration.rst b/docs/src/cdist-configuration.rst
index 4c9b4d33..706ed761 100644
--- a/docs/src/cdist-configuration.rst
+++ b/docs/src/cdist-configuration.rst
@@ -31,73 +31,11 @@ can be used.
Config file format
------------------
+
cdist configuration file is in the INI file format. Currently it supports
only [GLOBAL] section.
-The possible keywords and their meanings are as follows:
-:strong:`archiving`
- Use specified archiving. Valid values include:
- 'none', 'tar', 'tgz', 'tbz2' and 'txz'.
+Here you can find configuration file skeleton:
-:strong:`beta`
- Enable beta functionality. It recognizes boolean values from
- 'yes'/'no', 'on'/'off', 'true'/'false' and '1'/'0'.
-
-:strong:`cache_path_pattern`
- Specify cache path pattern.
-
-:strong:`conf_dir`
- List of configuration directories separated with the character conventionally
- used by the operating system to separate search path components (as in PATH),
- such as ':' for POSIX or ';' for Windows.
- If also specified at command line then values from command line are
- appended to this value.
-
-:strong:`init_manifest`
- Specify default initial manifest.
-
-:strong:`inventory_dir`
- Specify inventory directory.
-
-:strong:`jobs`
- Specify number of jobs for parallel processing. If -1 then the default,
- number of CPU's in the system is used. If 0 then parallel processing in
- jobs is disabled. If set to positive number then specified maximum
- number of processes will be used.
-
-:strong:`local_shell`
- Shell command used for local execution.
-
-:strong:`out_path`
- Directory to save cdist output in.
-
-:strong:`parallel`
- Process hosts in parallel. If -1 then the default, number of CPU's in
- the system is used. If 0 then parallel processing of hosts is disabled.
- If set to positive number then specified maximum number of processes
- will be used.
-
-:strong:`remote_copy`
- Command to use for remote copy (should behave like scp).
-
-:strong:`remote_exec`
- Command to use for remote execution (should behave like ssh).
-
-:strong:`remote_out_path`
- Directory to save cdist output in on the target host.
-
-:strong:`remote_shell`
- Shell command at remote host used for remote execution.
-
-:strong:`save_output_streams`
- Enable/disable saving output streams (enabled by default).
- It recognizes boolean values from 'yes'/'no', 'on'/'off', 'true'/'false'
- and '1'/'0'.
-
-:strong:`timestamp`
- Timestamp log messages with the current local date and time
- in the format: YYYYMMDDHHMMSS.us.
-
-:strong:`verbosity`
- Set verbosity level. Valid values are:
- 'ERROR', 'WARNING', 'INFO', 'VERBOSE', 'DEBUG', 'TRACE' and 'OFF'.
+.. literalinclude:: cdist.cfg.skeleton
+ :language: ini
diff --git a/docs/src/cdist-install.rst b/docs/src/cdist-install.rst
index a9b7d6b5..880b9f8e 100644
--- a/docs/src/cdist-install.rst
+++ b/docs/src/cdist-install.rst
@@ -23,8 +23,6 @@ Target Hosts
Install cdist
-------------
-You can install cdist either from git or as a python package.
-
From git
~~~~~~~~
@@ -42,6 +40,7 @@ To install cdist, execute the following commands:
From version 4.2.0 cdist tags and releases are signed.
You can get GPG public key used for signing `here <_static/pgp-key-EFD2AE4EC36B6901.asc>`_.
+It is assumed that you are familiar with *git* ways of signing and verification.
You can also get cdist from `github mirror `_.
@@ -157,3 +156,27 @@ Cdist is available as a python package at
.. code-block:: sh
pip install cdist
+
+Installing from source with signature verification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you want to install cdist from signed source and verify it, first you need to
+download cdist archive and its detached signature.
+
+Get both, *cdist-x.y.z.tar.gz* and *cdist-x.y.z.tar.gz.asc* from release
+notes of the desired tag *x.y.z* at
+`cdist git repository `_.
+
+Get GPG public key used for signing `here <_static/pgp-key-EFD2AE4EC36B6901.asc>`_
+and import it into GPG.
+
+Now cdist source archive can be verified using `gpg`, e.g. to verify `cdist-6.2.0`:
+
+.. code-block:: sh
+
+ $ gpg --verify cdist-6.2.0.tar.gz.asc cdist-6.2.0.targ.gz
+ gpg: Signature made Sat Nov 30 23:14:19 2019 CET
+ gpg: using RSA key 69767822F3ECC3C349C1EFFFEFD2AE4EC36B6901
+ gpg: Good signature from "ungleich GmbH (ungleich FOSS) " [ultimate]
+
+Further steps are the same as for `installing from git `_.
diff --git a/docs/src/cdist-preos.rst b/docs/src/cdist-preos.rst
index e85af2de..9570bcfc 100644
--- a/docs/src/cdist-preos.rst
+++ b/docs/src/cdist-preos.rst
@@ -4,9 +4,9 @@ PreOS
Description
-----------
With cdist you can install and configure new machines. You can use cdist to
-create PreOS, minimal OS which purpose is to boot new machine.
-After PreOS is booted machine is ready for installing desired OS and
-then it is ready for configuration.
+create PreOS, minimal OS whose purpose is to boot a new machine.
+After PreOS is booted, the machine is ready for installing the desired OS and
+afterwards it is ready for configuration.
PreOS creation
--------------
@@ -15,62 +15,62 @@ Currently supported PreOS-es include:
* debian
* ubuntu
-* devuan.
+* devuan
-PreOS is created using cdist preos command. preos command has subcommands that
-create the desired PreOS.
+PreOS is created using the ``cdist preos`` command.
+This command has subcommands that determine the desired PreOS.
-For example, to create ubuntu PreOS:
+For example, to create an ubuntu PreOS:
.. code-block:: sh
$ cdist preos ubuntu /preos/preos-ubuntu -B -C \
-k ~/.ssh/id_rsa.pub -p /preos/pxe-ubuntu
-For more info about available options see cdist manual page.
+For more info about the available options see the cdist manual page.
-This will bootstrap (``-B``) ubuntu PreOS in ``/preos/preos-ubuntu`` directory, it
-will be configured (``-C``) using default built-in initial manifest and with
-specified ssh authorized key (``-k``).
-After bootstrapping and configuration PXE
-boot directory will be created (``-p``) in ``/preos/pxe-ubuntu``.
+This will bootstrap (``-B``) ubuntu PreOS in the ``/preos/preos-ubuntu``
+directory, it will be configured (``-C``) using default the built-in initial
+manifest and with specified ssh authorized key (``-k``).
+After bootstrapping and configuration, the PXE boot directory will be
+created (``-p``) in ``/preos/pxe-ubuntu``.
-After PreOS is created new machines can be booted using created PXE (after
-proper dhcp, tftp setting).
+After PreOS is created, new machines can be booted using the created PXE
+(after proper dhcp and tftp settings).
-Since PreOS is configured with ssh authorized key it can be accessed throguh
+Since PreOS is configured with ssh authorized key it can be accessed through
ssh, i.e. it can be further installed and configured with cdist.
-Implementing new PreOS sub-command
-----------------------------------
+Implementing a new PreOS sub-command
+------------------------------------
preos command is implemented as a plugin system. This plugin system scans for
-preos subcommands in ``cdist/preos/`` distribution directory and also in
+preos subcommands in the ``cdist/preos/`` distribution directory and also in
``~/.cdist/preos/`` directory if it exists.
preos subcommand is a module or a class that satisfies the following:
-* it has attribute ``_cdist_preos`` set to ``True``
-* it has function/method ``commandline``.
+* it has the attribute ``_cdist_preos`` set to ``True``
+* it defines a function/method ``commandline``.
-For a module based preos subcommand ``commandline`` function accepts a module
-object as its first argument and the list of command line
+For a module-based preos subcommand, the ``commandline`` function accepts a
+module object as its first argument and the list of command line
arguments (``sys.argv[2:]``).
-For a class preos subcommand ``commandline`` method should be staticmethod and
-it accepts a class object as its first argument and the list of command line
-arguments(``sys.argv[2:]``).
+For a class-based preos subcommand ``commandline`` method should be
+static-method and must accept a class as its first argument and the
+list of command line arguments (``sys.argv[2:]``).
If preos scanning finds a module/class that has ``_cdist_preos`` set
-to ``True`` and it has function/method ``commandline`` then this module/class is
+to ``True`` and a function/method ``commandline`` then this module/class is
registered to preos subcommands. The name of the command is set to ``_preos_name``
-attribute if it exists, otherwise it is set to the module/class name, lowercase.
-When registered preos subcommand is specified as preos command then ``commandline``
-will be called with first argument set to module/class object and second argument
-set to ``sys.argv[2:]``.
+attribute if defined in the module/class, defaulting to the module/class name in lowercase.
+When a registered preos subcommand is specified, ``commandline``
+will be called with the first argument set to module/class and the second
+argument set to ``sys.argv[2:]``.
-Example writing new dummy preos sub-command
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Module based preos:
+Example of writing new dummy preos sub-command
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Module-based preos:
^^^^^^^^^^^^^^^^^^^
#. Create directory ``~/.cdist/preos/`` if it does not exist
@@ -88,16 +88,12 @@ When you try to run this new preos you will get:
.. code-block:: sh
- $ cdist preos -h
- usage: cdist preos [-h] preos
-
- Create PreOS
-
- positional arguments:
- preos PreOS to create, one of: {'netbsd', 'debian', 'ubuntu'}
-
- optional arguments:
- -h, --help show this help message and exit
+ $ cdist preos -L
+ Available PreOS-es:
+ - debian
+ - devuan
+ - netbsd
+ - ubuntu
$ cdist preos netbsd
NetBSD PreOS: []
@@ -121,17 +117,13 @@ When you try to run this new preos you will get:
.. code-block:: sh
$ cdist preos -h
- usage: cdist preos [-h] preos
-
- Create PreOS
-
- positional arguments:
- preos PreOS to create, one of: {'freebsd', 'debian', 'ubuntu'}
-
- optional arguments:
- -h, --help show this help message and exit
+ Available PreOS-es:
+ - debian
+ - devuan
+ - freebsd
+ - ubuntu
$ cdist preos freebsd
FreeBSD dummy preos: []
In the ``commandline`` function/method you have all the freedom to actually create
-PreOS.
+a PreOS.
diff --git a/docs/src/cdist-types.rst b/docs/src/cdist-types.rst
deleted file mode 100644
index d5104667..00000000
--- a/docs/src/cdist-types.rst
+++ /dev/null
@@ -1,8 +0,0 @@
-cdist types
-===========
-
-.. toctree::
- :titlesonly:
- :glob:
-
- man7/*
diff --git a/docs/src/cdist-types.rst.sh b/docs/src/cdist-types.rst.sh
new file mode 100755
index 00000000..2eb66009
--- /dev/null
+++ b/docs/src/cdist-types.rst.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# 2019 Darko Poljak (darko.poljak at gmail.com)
+#
+# This file is part of cdist.
+#
+# cdist 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.
+#
+# cdist 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 cdist. If not, see .
+#
+#
+# Generate cdist-types.rst that lists available types.
+#
+
+__cdist_pwd="$(pwd -P)"
+__cdist_mydir="${0%/*}";
+__cdist_abs_mydir="$(cd "$__cdist_mydir" && pwd -P)"
+__cdist_myname=${0##*/};
+__cdist_abs_myname="$__cdist_abs_mydir/$__cdist_myname"
+
+filename="${__cdist_myname%.sh}"
+dest="$__cdist_abs_mydir/$filename"
+
+cd "$__cdist_abs_mydir"
+
+exec > "$dest"
+cat << eof
+cdist types
+===========
+
+.. toctree::
+ :titlesonly:
+
+eof
+
+# If there is no such file then ls prints error to stderr,
+# so redirect stderr to /dev/null.
+for type in $(ls man7/cdist-type__*.rst 2>/dev/null | LC_ALL=C sort); do
+ no_dir="${type#man7/}";
+ no_type="${no_dir#cdist-type}";
+ name="${no_type%.rst}";
+ manref="${no_dir%.rst}"
+ man="${manref}(7)"
+
+ echo " $name" ""
+done
diff --git a/docs/src/conf.py b/docs/src/conf.py
index 78f9842c..47765413 100644
--- a/docs/src/conf.py
+++ b/docs/src/conf.py
@@ -56,7 +56,7 @@ master_doc = 'index'
# General information about the project.
project = 'cdist'
-copyright = 'ungleich GmbH 2019'
+copyright = 'ungleich GmbH 2020'
# author = 'Darko Poljak'
# The version info for the project you're documenting, acts as replacement for
diff --git a/docs/src/index.rst b/docs/src/index.rst
index 5e54d8fc..31c044dc 100644
--- a/docs/src/index.rst
+++ b/docs/src/index.rst
@@ -2,8 +2,9 @@ cdist - usable configuration management
=======================================
cdist is a usable configuration management system.
-It adheres to the KISS principle and
+It adheres to the KISS principle and
is being used in small up to enterprise grade environments.
+It natively supports IPv6 since the first release.
.. toctree::
diff --git a/docs/src/man1/cdist.rst b/docs/src/man1/cdist.rst
index f40491e9..38248821 100644
--- a/docs/src/man1/cdist.rst
+++ b/docs/src/man1/cdist.rst
@@ -11,7 +11,7 @@ SYNOPSIS
::
- cdist [-h] [-V] {banner,config,install,inventory,preos,shell} ...
+ cdist [-h] [-V] {banner,config,install,inventory,preos,shell,info} ...
cdist banner [-h] [-l LOGLEVEL] [-q] [-v]
@@ -59,31 +59,35 @@ SYNOPSIS
[-I INVENTORY_DIR] [-a] [-f HOSTFILE] [-H] [-t]
[host [host ...]]
- cdist preos [-h] preos
+ cdist preos [-h] [-l LOGLEVEL] [-q] [-v] [-c CONF_DIR] [-g CONFIG_FILE]
+ [-L]
+ [preos] ...
- cdist preos debian [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-a ARCH] [-B]
- [-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
- [-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
- [-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
- [-S SCRIPT] [-s SUITE] [-y REMOTE_COPY]
- target_dir
+ cdist preos [preos-options] debian [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-a ARCH] [-B]
+ [-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
+ [-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
+ [-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
+ [-S SCRIPT] [-s SUITE] [-y REMOTE_COPY]
+ target_dir
- cdist preos devuan [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-a ARCH] [-B]
- [-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
- [-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
- [-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
- [-S SCRIPT] [-s SUITE] [-y REMOTE_COPY]
- target_dir
+ cdist preos [preos-options] devuan [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-a ARCH] [-B]
+ [-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
+ [-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
+ [-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
+ [-S SCRIPT] [-s SUITE] [-y REMOTE_COPY]
+ target_dir
- cdist preos ubuntu [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-a ARCH] [-B]
- [-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
- [-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
- [-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
- [-S SCRIPT] [-s SUITE] [-y REMOTE_COPY]
- target_dir
+ cdist preos [preos-options] ubuntu [-h] [-l LOGLEVEL] [-q] [-v] [-b] [-a ARCH] [-B]
+ [-C] [-c CDIST_PARAMS] [-D DRIVE] [-e REMOTE_EXEC]
+ [-i MANIFEST] [-k KEYFILE ] [-m MIRROR]
+ [-P ROOT_PASSWORD] [-p PXE_BOOT_DIR] [-r]
+ [-S SCRIPT] [-s SUITE] [-y REMOTE_COPY]
+ target_dir
cdist shell [-h] [-l LOGLEVEL] [-q] [-v] [-s SHELL]
+ cdist info [-h] [-a] [-c CONF_DIR] [-e] [-F] [-f] [-g CONFIG_FILE] [-t] [pattern]
+
DESCRIPTION
-----------
@@ -103,7 +107,7 @@ All commands accept the following options:
**-l LOGLEVEL, --log-level LOGLEVEL**
Set the specified verbosity level. The levels, in
order from the lowest to the highest, are: ERROR (-1),
- WARNING (0), INFO (1), VERBOSE (2), DEBUG (3) TRACE (4
+ WARNING (0), INFO (1), VERBOSE (2), DEBUG (3), TRACE (4
or higher). If used along with -v then -v increases
last set value and -l overwrites last set value.
@@ -116,7 +120,7 @@ All commands accept the following options:
value is 0 which includes ERROR and WARNING levels.
The levels, in order from the lowest to the highest,
are: ERROR (-1), WARNING (0), INFO (1), VERBOSE (2),
- DEBUG (3) TRACE (4 or higher). If used along with -l
+ DEBUG (3), TRACE (4 or higher). If used along with -l
then -l overwrites last set value and -v increases
last set value.
@@ -457,7 +461,18 @@ List inventory database.
PREOS
-----
-Create PreOS. Currently, the following PreOS-es are supported:
+Create PreOS.
+
+**-c CONF_DIR, --conf-dir CONF_DIR**
+ Add configuration directory (one that contains "preos" subdirectory).
+
+**-g CONFIG_FILE, --config-file CONFIG_FILE**
+ Use specified custom configuration file.
+
+**-L, --list-preoses**
+ List available PreOS-es.
+
+Currently, the following PreOS-es are supported:
* debian
* ubuntu
@@ -596,6 +611,39 @@ usage. Its primary use is for debugging type parameters.
be POSIX compatible shell.
+INFO
+----
+Display information for cdist (global explorers, types).
+
+**pattern**
+ Glob pattern. If it contains special characters('?', '*', '[') then it is
+ used as specified, otherwise it is translated to `*pattern*`.
+
+**-h, --help**
+ Show help message and exit.
+
+**-a, --all**
+ Display all info. This is the default.
+
+**-c CONF_DIR, --conf-dir CONF_DIR**
+ Add configuration directory (can be repeated).
+
+**-e, --global-explorers**
+ Display info for global explorers.
+
+**-F, --fixed-string**
+ Interpret pattern as a fixed string.
+
+**-f, --full**
+ Display full details.
+
+**-g CONFIG_FILE, --config-file CONFIG_FILE**
+ Use specified custom configuration file.
+
+**-t, --types**
+ Display info for types.
+
+
CONFIGURATION
-------------
cdist obtains configuration data from the following sources in the following
@@ -907,5 +955,5 @@ such case and display a warning message. An example of such a case:
COPYING
-------
-Copyright \(C) 2011-2017 Nico Schottelius. Free use of this software is
+Copyright \(C) 2011-2019 Nico Schottelius. Free use of this software is
granted under the terms of the GNU General Public License v3 or later (GPLv3+).
diff --git a/other/ci/Dockerfile b/other/ci/Dockerfile
new file mode 100644
index 00000000..03d6b546
--- /dev/null
+++ b/other/ci/Dockerfile
@@ -0,0 +1,8 @@
+FROM alpine:latest
+
+COPY ./repositories /etc/apk/
+
+RUN apk update
+RUN apk upgrade
+RUN apk add python3 py3-pycodestyle rsync make shellcheck git
+RUN apk fix
diff --git a/other/ci/README.md b/other/ci/README.md
new file mode 100644
index 00000000..6a9b0ac5
--- /dev/null
+++ b/other/ci/README.md
@@ -0,0 +1,3 @@
+This container is used for cdist's CI pipeline, and deployed in ungleich's docker registry at:
+
+ code.ungleich.ch:5050/ungleich-public/cdist/cdist-ci:latest
diff --git a/other/ci/repositories b/other/ci/repositories
new file mode 100644
index 00000000..46cabcc3
--- /dev/null
+++ b/other/ci/repositories
@@ -0,0 +1,3 @@
+https://mirror.ungleich.ch/mirror/packages/alpine/edge/main
+https://mirror.ungleich.ch/mirror/packages/alpine/edge/community
+https://mirror.ungleich.ch/mirror/packages/alpine/edge/testing
diff --git a/scripts/cdist-dump b/scripts/cdist-dump
index 83b09eb8..d29e5985 100755
--- a/scripts/cdist-dump
+++ b/scripts/cdist-dump
@@ -224,6 +224,7 @@ hor_line()
if [ "${do_global_explorer}" ]
then
print_verbose 2 "Dumping global explorers"
+ # shellcheck disable=SC2086
set -- "$@" ${or} \( \
-path "*/explorer/*" -a \
! -path "*/conf/*" -a \