diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dba7864..81db798 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,14 +1,29 @@ stages: - test + - doc -image: code.ungleich.ch:5050/ungleich-public/cdist/cdist-ci:latest +image: code.ungleich.ch:5050/ungleich-public/cdist-contrib/ci-container:latest shellcheck: stage: test script: - - ./scripts/run-shellcheck.sh + - make lint manpages: stage: test script: - - ./scripts/run-manpage-checks.sh + - make check-manpages + +docs: + stage: doc + only: + - master + before_script: + - eval $(ssh-agent -s) + - echo "$CD_SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null + - mkdir -p ~/.ssh + - echo "$CD_SSH_SERVER_HOSTKEYS" > ~/.ssh/known_hosts + - chmod 644 ~/.ssh/known_hosts + script: + - make html + - sftp fnux@staticwebhosting.ungleich.ch:public_html/cdist-contrib <<< "put -r docs/dist/html/*" diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index d2ebad0..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -# cdist-contrib changes - -* 2020-04-28: New type: __find_exec (Ander Punnar) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1a0cfb3 --- /dev/null +++ b/Makefile @@ -0,0 +1,70 @@ +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo "man build only man user documentation" + @echo "html build only html user documentation" + @echo "docs build both man and html user documentation" + @echo "check-manpages check for manpage in types" + @echo "lint run shellcheck on types" + @echo "check run both type manpage checks and linting" + @echo "clean clean" + +DOCS_SRC_DIR=./docs/src +TYPEDIR=./type + +SPHINXM=make -C $(DOCS_SRC_DIR) man +SPHINXH=make -C $(DOCS_SRC_DIR) html +SPHINXC=make -C $(DOCS_SRC_DIR) clean + +################################################################################ +# Manpages +# +MAN7DSTDIR=$(DOCS_SRC_DIR)/man7 + +# Use shell / ls to get complete list - $(TYPEDIR)/*/man.rst does not work +# Using ls does not work if no file with given pattern exist, so use wildcard +MANTYPESRC=$(wildcard $(TYPEDIR)/*/man.rst) +MANTYPEPREFIX=$(subst $(TYPEDIR)/,$(MAN7DSTDIR)/cdist-type,$(MANTYPESRC)) +MANTYPES=$(subst /man.rst,.rst,$(MANTYPEPREFIX)) + +# Link manpage: do not create man.html but correct named file +$(MAN7DSTDIR)/cdist-type%.rst: $(TYPEDIR)/%/man.rst + mkdir -p $(MAN7DSTDIR) + ln -sf "../../../$^" $@ + +DOCSINDEX=$(MAN7DSTDIR)/index.rst +DOCSINDEXH=$(DOCS_SRC_DIR)/index.rst.sh + +$(DOCSINDEX): $(DOCSINDEXH) + $(DOCSINDEXH) + +# Manpages: .cdist Types +DOT_CDIST_PATH=${HOME}/.cdist +DOTMAN7DSTDIR=$(MAN7DSTDIR) +DOTTYPEDIR=$(DOT_CDIST_PATH)/type + +# Link manpage: do not create man.html but correct named file +$(DOTMAN7DSTDIR)/cdist-type%.rst: $(DOTTYPEDIR)/%/man.rst + ln -sf "$^" $@ + +man: $(MANTYPES) $(DOCSINDEX) + $(SPHINXM) + +html: $(MANTYPES) $(DOCSINDEX) + $(SPHINXH) + +docs: man html + +check-manpages: + ./scripts/run-manpage-checks.sh + +lint: + ./scripts/run-shellcheck.sh + +check: check-manpages lint + +clean: + $(SPHINXC) + rm -f docs/src/index.rst + rm -rf docs/src/man7/ + rm -rf docs/src/__pycache__/ diff --git a/README.md b/README.md index ef4b2c3..28f54db 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,9 @@ tool with community-maitained types which are either too specific to fit/be maintained in cdist itself or were not accepted in code cdist but could still be useful. -This project does not have releases and is continously updated: see -`CHANGELOG.md` for details. +This project does not have releases and is continously updated: see git history +for change log. You will find HTML documentation at +[contrib.cdi.st](https://contrib.cdi.st). ## Using cdist-contrib @@ -32,14 +33,11 @@ And you would run [cdist][cdist] from the same directory as follows: ## Participating in the [cdist][cdist] community -Join us on [#cdist:ungleich.ch][cdistmatrix] on matrix or on -[#cdist over mattermost][cdistmattermost]. - +Join us on [#cdist:ungleich.ch][cdistmatrix] on matrix! [cdist]: https://www.cdi.st/ [cdistconfig]: https://www.cdi.st/manual/latest/cdist-configuration.html [cdistmatrix]: https://matrix.to/#/#cdist:ungleich.ch -[cdistmattermost]: https://chat.ungleich.ch/ungleich/channels/cdist ## Contributing @@ -53,3 +51,11 @@ Every type in cdist-contrib must: * Have a `man.rst` documentation page. * Pass [shellcheck](http://shellcheck.net/) without errors. + +## Other resources + +Some people/organizations are known to keep some cdist types that might be of +interest to others: + +* [cdist-evilham](https://git.sr.ht/~evilham/cdist-evilham): Evilham's cdist-types +* [cdist-recycledcloud](https://code.recycled.cloud/e-Durable/cdist-recycledcloud): e-Durable SA / Recycled Cloud public types diff --git a/docs/src/Makefile b/docs/src/Makefile new file mode 100644 index 0000000..2e9d6ce --- /dev/null +++ b/docs/src/Makefile @@ -0,0 +1,235 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +PAPER ?= +BUILDDIR ?= ../dist +# for cache, etc. +_BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) + $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(_BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + rm -rf $(_BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/cdist-docs.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/cdist-docs.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/cdist-docs" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/cdist-docs" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b cman $(ALLSPHINXOPTS) $(BUILDDIR)/man + mkdir -p $(BUILDDIR)/man/man7 + mv -f $(BUILDDIR)/man/*.7 $(BUILDDIR)/man/man7/ + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/docs/src/conf.py b/docs/src/conf.py new file mode 100644 index 0000000..19b2dfd --- /dev/null +++ b/docs/src/conf.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 + +import sys +import os +import sphinx_rtd_theme + +from datetime import date + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(os.path.join( + os.path.dirname(os.path.realpath(__file__)), "..", ".."))) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'docs.src.manpage', + 'sphinx.ext.extlinks', +] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +source_suffix = ['.rst'] + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'cdist-contrib' +copyright = 'cdist-contrib contributors' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + +version = str(date.today()) +release = os.popen('git rev-parse HEAD').read() + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'sphinx_rtd_theme' +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# Output file base name for HTML help builder. +htmlhelp_basename = 'cdistcontribdoc' + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +root_mandir = os.path.dirname(os.path.realpath(__file__)) +mandirs = [] +for mansubdir in ('man7',): + mandirs.append((os.path.join(root_mandir, mansubdir), mansubdir[-1])) +man_pages = [] +for mandir, section in mandirs: + for root, dirs, files in os.walk(mandir): + for fname in files: + froot, fext = os.path.splitext(fname) + if fext == '.rst': + man_page = (os.path.join('man' + str(section), froot), + froot, '', [], section) + man_pages.append(man_page) + +# man_pages = [ +# ('cdist-type', 'cdist-type', 'cdist-type documentation', +# [author], 1), +# ('man7/cdist-type__file', 'cdist-type__file', +# '', [], 1), +# ('cdist-type__directory', 'cdist-type__directory', +# 'cdist-type__directory documentation', [author], 1), +# ] + +# If true, show URL addresses after external links. +# man_show_urls = False diff --git a/docs/src/index.rst.sh b/docs/src/index.rst.sh new file mode 100755 index 0000000..babc1d9 --- /dev/null +++ b/docs/src/index.rst.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +__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" + +if ! command -v pandoc > /dev/null; then + echo "Pandoc is required to generate HTML index from README." >&2 + exit 1 +fi + +cd "$__cdist_abs_mydir" + +exec > "$dest" + +pandoc -f markdown -t rst ../../README.md + +cat << EOF + +.. toctree:: + :hidden: + +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/manpage.py b/docs/src/manpage.py new file mode 100644 index 0000000..1f8ac4f --- /dev/null +++ b/docs/src/manpage.py @@ -0,0 +1,87 @@ +import sphinx.builders.manpage +import sphinx.writers.manpage +from docutils.frontend import OptionParser +from sphinx.util.console import bold, darkgreen +from six import string_types +from docutils.io import FileOutput +from os import path +from sphinx.util.nodes import inline_all_toctrees +from sphinx import addnodes +from sphinx.util import logging + +""" + Extension based on sphinx builtin manpage. + It does not write its own .SH NAME based on config, + but leaves everything to actual reStructuredText file content. +""" + + +logger = logging.getLogger(__name__) + + +class ManualPageTranslator(sphinx.writers.manpage.ManualPageTranslator): + + def header(self): + tmpl = (".TH \"%(title_upper)s\" \"%(manual_section)s\"" + " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n") + return tmpl % self._docinfo + + +class ManualPageWriter(sphinx.writers.manpage.ManualPageWriter): + + def __init__(self, builder): + super().__init__(builder) + self.translator_class = ( + self.builder.get_translator_class() or ManualPageTranslator) + + +class ManualPageBuilder(sphinx.builders.manpage.ManualPageBuilder): + + name = 'cman' + default_translator_class = ManualPageTranslator + + def write(self, *ignored): + docwriter = ManualPageWriter(self) + docsettings = OptionParser( + defaults=self.env.settings, + components=(docwriter,), + read_config_files=True).get_default_values() + + logger.info(bold('writing... '), nonl=True) + + for info in self.config.man_pages: + docname, name, description, authors, section = info + if isinstance(authors, string_types): + if authors: + authors = [authors] + else: + authors = [] + + targetname = '%s.%s' % (name, section) + logger.info(darkgreen(targetname) + ' { ', nonl=True) + destination = FileOutput( + destination_path=path.join(self.outdir, targetname), + encoding='utf-8') + + tree = self.env.get_doctree(docname) + docnames = set() + largetree = inline_all_toctrees(self, docnames, docname, tree, + darkgreen, [docname]) + logger.info('} ', nonl=True) + self.env.resolve_references(largetree, docname, self) + # remove pending_xref nodes + for pendingnode in largetree.traverse(addnodes.pending_xref): + pendingnode.replace_self(pendingnode.children) + + largetree.settings = docsettings + largetree.settings.title = name + largetree.settings.subtitle = description + largetree.settings.authors = authors + largetree.settings.section = section + + docwriter.write(largetree, destination) + logger.info("") + + +def setup(app): + app.add_builder(ManualPageBuilder) diff --git a/scripts/ci-container/Dockerfile b/scripts/ci-container/Dockerfile new file mode 100644 index 0000000..9900322 --- /dev/null +++ b/scripts/ci-container/Dockerfile @@ -0,0 +1,7 @@ +# This image is used in the cdist-contrib CI for linting and generating the +# documentation. +FROM fedora:latest +MAINTAINER Timothée Floure + +RUN dnf install -y git findutils make python3-sphinx python3-sphinx_rtd_theme \ + ShellCheck openssh-clients pandoc diff --git a/scripts/run-shellcheck.sh b/scripts/run-shellcheck.sh index 769f853..d6c2db6 100755 --- a/scripts/run-shellcheck.sh +++ b/scripts/run-shellcheck.sh @@ -1,21 +1,29 @@ -#!/bin/sh +#!/bin/sh -eu -SHELLCHECKCMD="shellcheck -s sh -f gcc -x" +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" +SHELLCHECKTMP='.shellcheck.tmp' # Move to top-level cdist-contrib directory. -cd $(dirname $0)/.. +cd "$(dirname $0)"/.. -check () { - find type/ -type f $1 $2 -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" > "${SHELLCHECKTMP}" - test ! -s "${SHELLCHECKTMP}" || { cat "${SHELLCHECKTMP}"; exit 1; } +check() { + find type/ -type f "$@" -exec ${SHELLCHECKCMD} {} + \ + | grep -v "${SHELLCHECK_SKIP}" >>"${SHELLCHECKTMP}" || true } -check -path "*/explorer/*" -check -path "*/files/*" +rm -f "${SHELLCHECKTMP}" + +check -path '*/explorer/*' +check -path '*/files/*' -name '*.sh' check -name manifest check -name gencode-local check -name gencode-remote + +if test -s "${SHELLCHECKTMP}" +then + cat "${SHELLCHECKTMP}" >&2 + exit 1 +fi diff --git a/type/__borg_repo/gencode-remote b/type/__borg_repo/gencode-remote new file mode 100644 index 0000000..542bf5f --- /dev/null +++ b/type/__borg_repo/gencode-remote @@ -0,0 +1,36 @@ +#!/bin/sh + +passphrase= +appendonly= + +case "$(cat "${__object:?}/parameter/encryption")" in + none) + enc=none + ;; + repokey) + enc=repokey + if [ -f "${__object:?}/parameter/passphrase" ]; + then + passphrase="$(cat "${__object:?}/parameter/passphrase")" + else + echo "__borg_repo cannot use repokey encryption with no passphrase. Aborting." >&2; + exit 1; + fi + ;; + *) + echo "$enc is not a known encryption mode for __borg_repo. Aborting." >&2 + exit 1; +esac + +if [ -f "${__object:?}/parameter/append-only" ]; +then + appendonly='--append-only' +fi + +cat <<- EOF + if ! borg check --repository-only 1>&2 2>/dev/null "/${__object_id:?}"; + then + BORG_NEW_PASSPHRASE=$passphrase borg init -e ${enc:?} $appendonly /${__object_id:?} + fi +EOF + diff --git a/type/__borg_repo/man.rst b/type/__borg_repo/man.rst new file mode 100644 index 0000000..38ab0c9 --- /dev/null +++ b/type/__borg_repo/man.rst @@ -0,0 +1,43 @@ +cdist-type__borg_repo(7) +======================== + +NAME +---- +cdist-type__borg_repo - Configure a borg repository on host + + +DESCRIPTION +----------- + +Initializes a borg repository at the location specified in the +`${__object_id}`. Nothing is done if the repository already exists. + +Currently, only `none` and `repokey` are supported as encryption modes; +`repokey` requires the `passphrase` argument to be given. The default is +`none`. + +REQUIRED PARAMETERS +------------------- +encryption + The encryption to use. + +OPTIONAL PARAMETERS +------------------- +passphrase + The passphrase to encrypt the keyfile with. + +BOOLEAN PARAMETERS +------------------ +append-only + If the repository is append-only + +AUTHORS +------- +Joachim Desroches + +COPYING +------- +Copyright \(C) 2020 Joachim Desroches. 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/type/__borg_repo/manifest b/type/__borg_repo/manifest new file mode 100644 index 0000000..fe18c9c --- /dev/null +++ b/type/__borg_repo/manifest @@ -0,0 +1,14 @@ +#!/bin/sh + +os="$(cat "${__global:?}"/explorer/os)" + +case "$os" in + "alpine") + borg_package=borgbackup + ;; + *) + echo "__borg_repo is not yet implemented for os $os. Aborting." >&2; + exit 1; +esac + +__package "$borg_package" diff --git a/type/__borg_repo/parameter/boolean b/type/__borg_repo/parameter/boolean new file mode 100644 index 0000000..f8ee7c6 --- /dev/null +++ b/type/__borg_repo/parameter/boolean @@ -0,0 +1 @@ +append-only diff --git a/type/__borg_repo/parameter/default/encryption b/type/__borg_repo/parameter/default/encryption new file mode 100644 index 0000000..621e94f --- /dev/null +++ b/type/__borg_repo/parameter/default/encryption @@ -0,0 +1 @@ +none diff --git a/type/__borg_repo/parameter/optional b/type/__borg_repo/parameter/optional new file mode 100644 index 0000000..f63b25b --- /dev/null +++ b/type/__borg_repo/parameter/optional @@ -0,0 +1 @@ +passphrase diff --git a/type/__borg_repo/parameter/required b/type/__borg_repo/parameter/required new file mode 100644 index 0000000..a5465f8 --- /dev/null +++ b/type/__borg_repo/parameter/required @@ -0,0 +1 @@ +encryption diff --git a/type/__dma/explorer/auth_conf b/type/__dma/explorer/auth_conf new file mode 100755 index 0000000..cef0aca --- /dev/null +++ b/type/__dma/explorer/auth_conf @@ -0,0 +1,49 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) +# +# 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 . +# +# This explorer determines the path of dma's auth.conf file + +# No dma.conf -> use default +test -f /etc/dma/dma.conf || { + echo /etc/dma/auth.conf + exit 0 +} +test -r /etc/dma/dma.conf || { + echo 'Cannot read /etc/dma/dma.conf' >&2 + exit 1 +} + +# Get AUTHPATH from dma.conf +awk -F'[ \t]' ' +{ + sub(/#.*$/, "", $0) # remove comments + if (!$0) next # ignore empty lines +} +$1 == "AUTHPATH" { + # Store authpath. In dma conf parsing last wins. + if ($2) authpath = substr($0, index($0, " ") + 1) +} +END { + if (authpath) { + print authpath + exit 0 + } else exit 1 +} +' /etc/dma/dma.conf \ +|| echo /etc/dma/auth.conf # default diff --git a/type/__dma/explorer/conf b/type/__dma/explorer/conf new file mode 100755 index 0000000..b4d6d26 --- /dev/null +++ b/type/__dma/explorer/conf @@ -0,0 +1,34 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) +# +# 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 . +# +# This explorer returns a sorted list of "active" (= non-commented) lines +# in the dma.conf file. +# "Trailing" line comments are stripped off. +# +# NOTE: This explorer assumes that the sort(1) utility supports the non-POXIX +# -s (stable sort) option. + +CONF_PATH=/etc/dma # set in Makefile +dma_conf="${CONF_PATH:?}/dma.conf" + +test -f "${dma_conf}" || exit 0 + +grep -v -e '^[ \t]*#\|^$' "${dma_conf}" \ +| sed -e 's/[ \t]*#.*$//' \ +| sort -s -k 1,1 diff --git a/type/__dma/files/update_dma_conf.awk b/type/__dma/files/update_dma_conf.awk new file mode 100644 index 0000000..15ef7bf --- /dev/null +++ b/type/__dma/files/update_dma_conf.awk @@ -0,0 +1,178 @@ +#!/usr/bin/awk -f +# +# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) +# +# 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 . + +function comment_line(line) { + # returns the position in line at which the comment's text starts + # (0 if the line is not a comment) + match(line, /^[ \t]*\#+[ \t]*/) + return RSTART ? (RLENGTH + 1) : 0 +} +function empty_line(line) { return line ~ /^[ \t]*$/ } +function is_word(s) { return s ~ /^[A-Z_]+$/ } # "looks like a plausible word" + +function first(line, sep_re) { + # returns the part of the line until sep is found + # (or the whole line if sep is not found) + if (!sep_re) sep_re = "[" SUBSEP "]" + match(line, sep_re) + return RSTART ? substr(line, 1, RSTART - 1) : line +} + +function rest(line, sep_re) { + # returns the part of the line after the first occurrence of sep is found. + # (or nothing if sep is not found) + if (!sep_re) sep_re = "[" SUBSEP "]" + if (match(line, sep_re)) + return substr(line, RSTART + RLENGTH) +} + +function conf_pop(word, value) { + # returns the next value for the config `word` and delete it from the list. + # if value is set, this function will only return value if it is the first + # option in the list, otherwise it returns 0. + + if (!(word in conf)) return 0 + if (!value) { + if (index(conf[word], SUBSEP)) # more than one element? + value = substr(conf[word], 1, index(conf[word], SUBSEP) - 1) + else + value = conf[word] + } + + if (index(conf[word], SUBSEP)) { + if (index(conf[word], value SUBSEP) != 1) return 0 + conf[word] = substr(conf[word], length(value) + 2) + } else { + if (conf[word] != value) return 0 + delete conf[word] + } + return value +} + +function print_conf(word, value) { + # print a config line with the given parameters + printf "%s", word + if (value) printf " %s", value + printf "\n" +} + +function print_confs(word, value) { + # print config lines for all values stored in conf[word]. + if (!(word in conf)) return + if (conf[word]) { + while (value = conf_pop(word)) + print_conf(word, value) + } else { + print_conf(word) + delete conf[word] + } +} + +BEGIN { + FS = "\n" + EQS = "[ \t]" # copied from dma/conf.c + + if (ARGV[2]) exit (e=1) + + # Loop over file twice! + ARGV[2] = ARGV[1] + ARGC++ + + # read the "should" state into the `conf` array. + while (getline < "/dev/stdin") { + word = first($0, EQS) + if ((word in conf)) + conf[word] = conf[word] SUBSEP rest($0, EQS) + else + conf[word] = rest($0, EQS) + } +} + +# first pass, gather information about where which information is stored in the +# current config file. This information will be used in the second pass. +NR == FNR { + if (comment_line($0)) { + # comment line + word = first(substr($0, comment_line($0)), " ") + if (is_word(word)) last_occ["#" word] = FNR + } else { + word = first($0, EQS) + if (is_word(word)) last_occ[word] = FNR + } +} + +# before second pass prepare hashes containing location information to be used +# in the second pass. +NR > FNR && FNR == 1 { + # First we drop the locations of commented-out options if a non-commented + # option is available. If a non-commented option is available, we will + # append new config options there to have them all at one place. + for (k in last_occ) + if (k ~ /^\#/ && (substr(k, 2) in last_occ)) + delete last_occ[k] + + # Reverse the option => line mapping. The line_map allows for easier lookups + # in the second pass. + for (k in last_occ) line_map[last_occ[k]] = k +} + +# second pass, generate and output new config +NR > FNR { + if (comment_line($0) || empty_line($0)) { + # comment or empty line + print + + if ((FNR in line_map)) { + if (line_map[FNR] ~ /^\#/) { + # This line contains a commented config option. If the conf hash + # contains options to be set, we output them here because this + # option is not used in the current config. + k = substr(line_map[FNR], 2) + if ((k in conf)) print_confs(k) + } + + if (("INSECURE" in conf) && line_map[FNR] ~ /^\#?SECURE$/) { + # INSECURE goes where SECURE comment is. + print_confs("INSECURE") + } + } + } else { + word = first($0, EQS) + value = rest($0, EQS) + sub(/[ \t]*\#.*$/, "", value) # ignore comments in value + + if ((word in conf) && value == first(conf[word])) { + # keep config options we want + conf_pop(word) + print + } + + if ((FNR in line_map) && line_map[FNR] == word) { + # rest of config options should be here + print_confs(word) + } + } +} + +END { + if (e) exit + + # print rest of config options ( + for (word in conf) print_confs(word) +} diff --git a/type/__dma/gencode-remote b/type/__dma/gencode-remote new file mode 100755 index 0000000..580b22e --- /dev/null +++ b/type/__dma/gencode-remote @@ -0,0 +1,177 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# 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 . +# + +quote() { printf "'%s'" "$(printf '%s' "$*" | sed -e "s/'/'\\\\''/g")"; } +drop_awk_comments() { quote "$(sed '/^[[:blank:]]*#.*$/d;/^$/d' "$@")"; } + +CONF_PATH=/etc/dma # set in Makefile + +# Determine mailname +if test -f "${__object:?}/parameter/mailname" +then + mailname=$(cat "${__object:?}/parameter/mailname") +else + case $(cat "${__global:?}/explorer/os") + in + (debian|devuan|ubuntu) + # On Debian-like systems use /etc/mailname unless --mailname is used + mailname='/etc/mailname' + ;; + (*) + mailname=${__target_fqdn:?} + ;; + esac +fi + + +# Generate "should" values for config +conf_should=$( + if test -s "${__object:?}/parameter/smarthost" + then + printf 'SMARTHOST %s\n' "$(cat "${__object:?}/parameter/smarthost")" + fi + + printf 'MAILNAME %s\n' "${mailname}" + + if test -s "${__object:?}/explorer/auth_conf" + then + printf "AUTHPATH %s\n" "$(cat "${__object:?}/explorer/auth_conf")" + fi + + case $(cat "${__object:?}/parameter/security") + in + (ssl|tls) + default_smtp_port=465 + echo 'SECURETRANSFER' + ;; + (starttls) + default_smtp_port=587 + echo 'SECURETRANSFER' + echo 'STARTTLS' + ;; + (opportunistic) + default_smtp_port=25 + echo 'SECURETRANSFER' + echo 'STARTTLS' + echo 'OPPORTUNISTIC_TLS' + ;; + (insecure) + default_smtp_port=25 + echo 'INSECURE' + ;; + esac + + if test -s "${__object:?}/parameter/port" + then + printf 'PORT %u\n' "$(cat "${__object:?}/parameter/port")" + elif test "${default_smtp_port}" -ne 25 # DMA uses port 25 by default + then + printf 'PORT %u\n' "${default_smtp_port}" + fi + + if test -f "${__object:?}/parameter/masquerade" + then + while read -r line + do + printf 'MASQUERADE %s\n' "${line}" + done <"${__object:?}/parameter/masquerade" + fi + + if test -f "${__object:?}/parameter/defer" + then + echo 'DEFER' + fi + + if test -f "${__object:?}/parameter/fullbounce" + then + echo 'FULLBOUNCE' + fi + + if test -f "${__object:?}/parameter/nullclient" + then + test -s "${__object:?}/parameter/smarthost" || { + echo '--nullclient requires a --smarthost to be defined' >&2 + exit 1 + } + + echo 'NULLCLIENT' + fi +) +# Sort conf_should to compare against "conf_is" +conf_should=$(echo "${conf_should}" | sort -s -k 1,1) + +config_updated=false +if ! echo "${conf_should}" | cmp -s "${__object:?}/explorer/conf" - +then + # config needs to be updated + dma_conf="${CONF_PATH:?}/dma.conf" + + # The following AWK script will output the new config file to be stored on + # disk. To do so it reads the current dma.conf file and the config options + # that should be set (from stdin). + # Note that the path to the current dma.conf is passed to AWK twice, because + # the new file cannot be generated in one pass. + + # The logic tries to place options at a sensible location, that is: + # a) if the option is already used in the config file: + # group all similar options (e.g. MASQUERADE) at one place in the order + # they are listed in stdin. + # b) if it is a new option and a "default comment" (e.g. "#PORT 25") exists: + # place options grouped directly after the comment (the comment is left + # alone) + # c) otherwise: + # options are grouped by word (the first word in the line) and appended + # at the end of the file. + + cat <<-CODE + awk $(drop_awk_comments "${__type:?}/files/update_dma_conf.awk") $(quote "${dma_conf}") <<'EOF' >$(quote "${dma_conf}.tmp") \ + && cat $(quote "${dma_conf}.tmp") >$(quote "${dma_conf}") + ${conf_should} + EOF + rm $(quote "${dma_conf}.tmp") + CODE + + config_updated=true + echo 'config updated' >>"${__messages_out:?}" +fi + + +# Send a test email if enabled and necessary (=configuration changed) +if test -f "${__object:?}/parameter/send-test-mail" +then + if grep -q '^__mail_alias/root:' "${__messages_in:?}" \ + || grep -q '^__dma_auth/' "${__messages_in:?}" \ + || ${config_updated} + then + cat <<-CODE + sendmail root <<'EOF' + Subject: [cdist] Test mail from '${__target_fqdn:?}' + + Hi, + + you can ignore this message. + Its sole purpose is to notify you that root mail on ${__target_fqdn:?} + will be redirected to you. + + Enjoy! + EOF + CODE + fi +fi diff --git a/type/__dma/man.rst b/type/__dma/man.rst new file mode 100644 index 0000000..29a71fa --- /dev/null +++ b/type/__dma/man.rst @@ -0,0 +1,112 @@ +cdist-type__dma(7) +============================ + +NAME +---- +cdist-type__dma - Setup the DragonFly Mail Agent as the MTA. + + +DESCRIPTION +----------- +This (singleton) type uses DMA, a small Mail Transport Agent (MTA), to accept +mails from locally installed Mail User Agents (MUA) and either deliver the mails +to a remote smart host for delivery or communicate with remote SMTP servers +directly. + + +REQUIRED PARAMETERS +------------------- +None. + + +BOOLEAN PARAMETERS +------------------ +defer + If enabled, mail will not be sent immediately, but stored in a queue. + To flush the queue and send the mails, ```dma -q`` has to be run + periodically (e.g. using a cron job.) + This type does not manage such a cron job, but some operating systems ship + such a cron job with the package. +fullbounce + Enable if bounce messages should include the complete original message, + not just the headers. +nullclient + Enable to bypass aliases and local delivery, and instead forward all mails + to the defined ``--smarthost``. +send-test-mail + If set, this type will send a test email to root after setup, to check if + the configured settings work. + + +OPTIONAL PARAMETERS +------------------- +mailname + If present, this will be the hostname used to identify this host and the + remote part of the sender addresses. + If not defined, it defaults to ``/etc/mailname`` on Debian derivatives and + to ``__target_fqdn`` otherwise. + See `dma(8)` for more information. + + Note: on Debian derivatives the ``/etc/mailname`` file should be updated + instead of using this parameter. +masquerade + Masquerade the envelope-from addresses with this address/hostname. + Use this setting if mails are not accepted by destination mail servers + because your sender domain is invalid. + This option can be used multiple times. + For more information see the `dma(8)` man page. +port + The port on which to deliver email. + If not provided, a sensible default port will be used based on the + ``--security`` argument. +security + Configures whether and how DMA should use secure connections. + + ssl/tls + Enable TLS/SSL secured transfer. + starttls + Use STARTTLS to establish a secure connection. + opportunistic (default) + Will try to establish a secure connection using STARTTLS, but allow + unencrypted transfer if STARTTLS fails. + Most useful when dma is used without a smarthost, delivering remote + messages directly to the outside mail exchangers. + insecure + allow plain text SMTP login over an insecure connection. + Should really *not* be used anymore! +smarthost + The mail server used to send email. + It must be configured to act as a relay for the host being configured by + this type so that mail can be sent to users non-local to the smarthost. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Install DMA and use the smarthost mx1.domain.tld to send mail. + __dma --smarthost mx1.domain.tld --send-test-mail + + # Install DMA in a default configuration. + __dma + + +SEE ALSO +-------- +- `DragonFly Mail Agent `_ +- `DragonFly Handbook MTA `_ + + +AUTHORS +------- +Evilham +Dennis Camera + + +COPYING +------- +Copyright \(C) 2020 Evilham and Dennis Camera. 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/type/__dma/manifest b/type/__dma/manifest new file mode 100755 index 0000000..530ad09 --- /dev/null +++ b/type/__dma/manifest @@ -0,0 +1,66 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# 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 . +# + +os=$(cat "${__global:?}/explorer/os") + +# Install DMA +case ${os} +in + (alpine) + __package dma --state present + export require='__package/dma' + ;; + (debian|devuan|ubuntu) + __package dma --state present + export require='__package/dma' + ;; + (freebsd) + # Stop sendmail if necessary + __process 'sendmail' --name 'sendmail.*' --state absent \ + --stop '/etc/rc.d/sendmail onestop' + + # ... and disable it + __key_value 'rcconf-sendmail-enable' --file '/etc/rc.conf' \ + --key 'sendmail_enable' --delimiter '=' --value '"NONE"' \ + --exact_delimiter + + # Setup mailwrapper accordingly + __file '/etc/mail/mailer.conf' --mode 0644 --source - <<-'EOF' + # + # Execute the "real" sendmail program, named /usr/libexec/sendmail/sendmail + # + sendmail /usr/libexec/dma + send-mail /usr/libexec/dma + mailq /usr/libexec/dma + newaliases /usr/libexec/dma + rmail /usr/libexec/dma + EOF + ;; + (*) + cat <&2 +Your OS (${os}) is not supported yet. + +Maybe adding support is as simple as adapting the packages or allowing it, +we highly encourage you to open a PR with the necessary changes. +See: https://code.ungleich.ch/ungleich-public/cdist-contrib/ +EOF + exit 1 + ;; +esac diff --git a/type/__dma/parameter/boolean b/type/__dma/parameter/boolean new file mode 100644 index 0000000..523bb97 --- /dev/null +++ b/type/__dma/parameter/boolean @@ -0,0 +1,4 @@ +defer +fullbounce +nullclient +send-test-mail diff --git a/type/__dma/parameter/default/security b/type/__dma/parameter/default/security new file mode 100644 index 0000000..9f1e0a6 --- /dev/null +++ b/type/__dma/parameter/default/security @@ -0,0 +1 @@ +opportunistic diff --git a/type/__dma/parameter/optional b/type/__dma/parameter/optional new file mode 100644 index 0000000..615c189 --- /dev/null +++ b/type/__dma/parameter/optional @@ -0,0 +1,4 @@ +mailname +port +security +smarthost diff --git a/type/__dma/parameter/optional_multiple b/type/__dma/parameter/optional_multiple new file mode 100644 index 0000000..70f4146 --- /dev/null +++ b/type/__dma/parameter/optional_multiple @@ -0,0 +1 @@ +masquerade diff --git a/type/__root_mail_dma/singleton b/type/__dma/singleton similarity index 100% rename from type/__root_mail_dma/singleton rename to type/__dma/singleton diff --git a/type/__dma_auth/explorer/auth_conf b/type/__dma_auth/explorer/auth_conf new file mode 120000 index 0000000..e89de93 --- /dev/null +++ b/type/__dma_auth/explorer/auth_conf @@ -0,0 +1 @@ +../../__dma/explorer/auth_conf \ No newline at end of file diff --git a/type/__dma_auth/explorer/state b/type/__dma_auth/explorer/state new file mode 100755 index 0000000..c829cd4 --- /dev/null +++ b/type/__dma_auth/explorer/state @@ -0,0 +1,91 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) +# +# 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 . +# +# This explorer looks for a line matching the server parameter +# in dma's auth.conf and reports: +# present: a line matching login + host + password exists +# absent: no line matching login + host exists +# different_login: a line exists but with a different login user +# different_password: a line exists but with a different password +# multiple: multiple lines matching host exist (should not happen) + +auth_conf=$("${__type_explorer:?}/auth_conf") +test -r "${auth_conf}" || exit 0 + +awk -F'\n' ' +function getvalue(path) { + # Reads the first line of the file located at path and returns it. + getline < path + close(path) + return $0 +} + +BEGIN { + DP = "[: \t]" # copied from dma/conf.c + + parameter_dir = ENVIRON["__object"] "/parameter/" + + # Read the parameters of this object + host_param = ENVIRON["__object_id"] + login_param = getvalue(parameter_dir "login") + passwd_param = getvalue(parameter_dir "password") + + state = "absent" +} + +/^#/ || /^$/ { + # skip comments and empty lines + next +} + +{ + # parse line + + login = substr($0, 1, index($0, "|") - 1) + if (!login) { login = $0 } # if no "|" found + + host = substr($0, length(login) + 2) + + if (match(host, DP)) { + passwd = substr(host, RSTART + 1) + host = substr(host, 1, RSTART - 1) + } else { + passwd = "" + } +} + +host == host_param { + # a match… + if (state == "absent") { + if (login != login_param) + state = "different_login" + else if (passwd != passwd_param) + state = "different_password" + else + state = "present" + } else { + # report "multiple" to that the type can remove the duplicates. + state = "multiple" + } +} + +END { + print state +} +' "${auth_conf}" diff --git a/type/__dma_auth/files/update_dma_auth.awk b/type/__dma_auth/files/update_dma_auth.awk new file mode 100644 index 0000000..c50198b --- /dev/null +++ b/type/__dma_auth/files/update_dma_auth.awk @@ -0,0 +1,93 @@ +#!/usr/bin/awk -f +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# 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 . +# + +function getvalue(path) { + # Reads the first line of the file located at path and returns it. + getline < path + close(path) + return $0 +} + +function print_should() { + printf "%s|%s:%s\n", login_param, host_param, passwd_param +} + +BEGIN { + FS = "\n" + DP = "[: \t]" # copied from dma/conf.c + + parameter_dir = ENVIRON["__object"] "/parameter/" + + mode = (getvalue(parameter_dir "state") != "absent") + + host_param = ENVIRON["__object_id"] + login_param = getvalue(parameter_dir "login") + passwd_param = getvalue(parameter_dir "password") +} + +# skip comments and empty lines +/^#/ || /^$/ { + print + next +} + +{ + # parse line (like dma/conf.c would) + + login = substr($0, 1, index($0, "|") - 1) + if (!login) { login = $0 } # if no "|" found + + host = substr($0, length(login) + 2) + + if (match(host, DP)) { + passwd = substr(host, RSTART + 1) + host = substr(host, 1, RSTART - 1) + } else { + passwd = "" + } +} + +host == host_param { + if (mode) { + # state_should == present + if (!written) { + # replace first line if host matches (but only if no line has + # been written already -> no duplicates) + print_should() + written = 1 + } + next + } else { + # state_should == absent + next + } +} + +# leave other lines alone +{ + print +} + +END { + if (mode && !written) { + # append line if no match to replace was found + print_should() + } +} diff --git a/type/__dma_auth/gencode-remote b/type/__dma_auth/gencode-remote new file mode 100755 index 0000000..b6a0100 --- /dev/null +++ b/type/__dma_auth/gencode-remote @@ -0,0 +1,72 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# 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 . +# + +quote() { printf "'%s'" "$(printf '%s' "$*" | sed -e "s/'/'\\\\''/g")"; } +drop_awk_comments() { quote "$(sed '/^[[:blank:]]*#.*$/d;/^$/d' "$@")"; } + +state_is=$(cat "${__object:?}/explorer/state") +state_should=$(cat "${__object:?}/parameter/state") + +server=${__object_id:?} +login=$(cat "${__object:?}/parameter/login") + + +auth_conf=$(cat "${__object:?}/explorer/auth_conf") +test -n "${auth_conf}" || { + echo 'Cannot determine path of dma auth.conf' >&2 + exit 1 +} + +if test "${state_is}" = "${state_should}" +then + # state is as it should + exit 0 +fi + +case ${state_should} +in + (present) + test -n "${login}" || { echo '--login must be non-empty' >&2; exit 1; } + + if test "${state_is}" = 'absent' + then + printf 'add authuser %s on %s\n' "${login}" "${server}" >>"${__messages_out:?}" + else + printf 'set authuser %s on %s\n' "${login}" "${server}" >>"${__messages_out:?}" + fi + ;; + (absent) + printf 'delete authuser %s on %s\n' "${login}" "${server}" >>"${__messages_out:?}" + ;; + (*) + printf 'Invalid --state: %s.\n' "${state_should}" >&2 + printf 'Acceptable values are: present, absent.\n' >&2 + exit 1 + ;; +esac + + +cat <$(quote "${auth_conf}.tmp") \ +&& cat $(quote "${auth_conf}.tmp") >$(quote "${auth_conf}") +rm -f $(quote "${auth_conf}.tmp") +EOF diff --git a/type/__dma_auth/man.rst b/type/__dma_auth/man.rst new file mode 100644 index 0000000..da76883 --- /dev/null +++ b/type/__dma_auth/man.rst @@ -0,0 +1,66 @@ +cdist-type__dma_auth(7) +======================= + +NAME +---- +cdist-type__dma_auth - Configure SMTP logins for the DragonFly Mail Agent MTA. + + +DESCRIPTION +----------- +This cdist type allows you to set up credentials to log in to remote SMTP +servers. + +NB: dma currently (v0.13) does not differentiate between users on a host. + It will use whatever user it finds in the ``auth.conf`` first. + Thus, this type will use the ``__object_id`` as the host specifier. + + +REQUIRED PARAMETERS +------------------- +login + The user's LOGIN name on the SMTP server. +password + The user's password (in plain text.) + + +OPTIONAL PARAMETERS +------------------- +state + Either ``present`` or ``absent``. Defaults to ``present``. + +BOOLEAN PARAMETERS +------------------ +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Set the password for smarthost + __dma_auth smarthost.example.com --login joe --password hunter2 + + # Set credentials for user at an external provider + __dma_auth mail.provider.com --login paul@example.com --password letmein + + # Delete credentials for example.com (for all users) + __dma_auth example.com --login '' --password '' --state absent + +SEE ALSO +-------- +:strong:`cdist-type__dma`\ (7), :strong:`dma`\ (8) + + +AUTHORS +------- +Dennis Camera + + +COPYING +------- +Copyright \(C) 2020 Dennis Camera. 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/type/__dma_auth/nonparallel b/type/__dma_auth/nonparallel new file mode 100644 index 0000000..e69de29 diff --git a/type/__dma_auth/parameter/default/state b/type/__dma_auth/parameter/default/state new file mode 100644 index 0000000..e7f6134 --- /dev/null +++ b/type/__dma_auth/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/type/__dma_auth/parameter/optional b/type/__dma_auth/parameter/optional new file mode 100644 index 0000000..ff72b5c --- /dev/null +++ b/type/__dma_auth/parameter/optional @@ -0,0 +1 @@ +state diff --git a/type/__dma_auth/parameter/required b/type/__dma_auth/parameter/required new file mode 100644 index 0000000..ae3c622 --- /dev/null +++ b/type/__dma_auth/parameter/required @@ -0,0 +1,2 @@ +login +password diff --git a/type/__jitsi_meet/explorer/prometheus-jitsi-meet-explorer-version b/type/__jitsi_meet/explorer/prometheus-jitsi-meet-explorer-version new file mode 100755 index 0000000..b1cec48 --- /dev/null +++ b/type/__jitsi_meet/explorer/prometheus-jitsi-meet-explorer-version @@ -0,0 +1,7 @@ +#!/bin/sh -e + +EXPORTER_VERSION_FILE="/usr/local/bin/.prometheus-jitsi-meet-exporter.cdist.version" + +if [ -f "${EXPORTER_VERSION_FILE}" ]; then + cat "${EXPORTER_VERSION_FILE}" +fi diff --git a/type/__jitsi_meet/files/debconf_settings.sh b/type/__jitsi_meet/files/debconf_settings.sh new file mode 100644 index 0000000..9e358f0 --- /dev/null +++ b/type/__jitsi_meet/files/debconf_settings.sh @@ -0,0 +1,56 @@ +#!/bin/sh -e + +# This can be obtained with debconf-get-selections on a host with jitsi +# (and also analysing the deb-src) +if false; then + # We are currently not using these, just here as documentation + DEBCONF_SETTINGS="$(cat < + + +COPYING +------- +Copyright \(C) 2020 Evilham. diff --git a/type/__jitsi_meet/manifest b/type/__jitsi_meet/manifest new file mode 100755 index 0000000..d4d16dc --- /dev/null +++ b/type/__jitsi_meet/manifest @@ -0,0 +1,197 @@ +#!/bin/sh -e + +os="$(cat "${__global}/explorer/os")" +init="$(cat "${__global}/explorer/init")" +case "${os}" in + devuan|debian) + ;; + *) + echo "Your OS '${os}' is currently not supported." > /dev/stderr + exit 1 + ;; +esac + + +JITSI_HOST="${__target_host}" +TURN_SERVER="$(cat "${__object}/parameter/turn-server")" +TURN_SECRET="$(cat "${__object}/parameter/turn-secret")" + +if [ -z "${TURN_SERVER}" ]; then + TURN_SERVER="${JITSI_HOST}" +fi + +PROMETHEUS_JITSI_EXPORTER_IS_VERSION="$(cat "${__object}/explorer/prometheus-jitsi-meet-explorer-version")" + +# The rest is loosely based on Jitsi's documentation +# https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-quickstart + +# Setup repositories +## First the signing keys +__package gnupg2 +require="__package/gnupg2" __apt_key_uri jitsi_meet \ + --name 'Jitsi ' \ + --uri https://download.jitsi.org/jitsi-key.gpg.key \ + --state present +## Now the repositories (they are a tad weird, so distribution is 'stable/') +require="__apt_key_uri/jitsi_meet" __apt_source jitsi_meet \ + --uri 'https://download.jitsi.org' \ + --distribution 'stable/' \ + --state present +## Ensure apt cache is up-to-date +require="__apt_source/jitsi_meet" __apt_update_index + +export require="${require} __apt_source/jitsi_meet __apt_update_index" + +# Pre-feed debconf settings, so Jitsi's installation has a good config +# shellcheck source=type/__jitsi_meet/files/debconf_settings.sh +. "${__type}/files/debconf_settings.sh" # This defines DEBCONF_SETTINGS +__debconf_set_selections jitsi_meet --file - <&1 +EOF + + export require="__runit_service/prometheus-jitsi-meet-exporter" + JITSI_MEET_EXPORTER_SERVICE="sv %s prometheus-jitsi-meet-exporter" + ;; + systemd) + __systemd_unit prometheus-jitsi-meet-exporter.service \ + --source "-" \ + --enablement-state "enabled" <${JITSI_HOST}' + }, + + // BOSH URL. FIXME: use XEP-0156 to discover it. + bosh: '//${JITSI_HOST}/http-bind', + + // Websocket URL + // websocket: 'wss://${JITSI_HOST}/xmpp-websocket', + + // The name of client node advertised in XEP-0115 'c' stanza + clientNode: 'http://jitsi.org/jitsimeet', + + // The real JID of focus participant - can be overridden here + // Do not change username - FIXME: Make focus username configurable + // https://github.com/jitsi/jitsi-meet/issues/7376 + // focusUserJid: 'focus@auth.${JITSI_HOST}', + + + // Testing / experimental features. + // + + testing: { + // Disables the End to End Encryption feature. Useful for debugging + // issues related to insertable streams. + // disableE2EE: false, + + // P2P test mode disables automatic switching to P2P when there are 2 + // participants in the conference. + p2pTestMode: false + + // Enables the test specific features consumed by jitsi-meet-torture + // testMode: false + + // Disables the auto-play behavior of *all* newly created video element. + // This is useful when the client runs on a host with limited resources. + // noAutoPlayVideo: false + + // Enable / disable 500 Kbps bitrate cap on desktop tracks. When enabled, + // simulcast is turned off for the desktop share. If presenter is turned + // on while screensharing is in progress, the max bitrate is automatically + // adjusted to 2.5 Mbps. This takes a value between 0 and 1 which determines + // the probability for this to be enabled. + // capScreenshareBitrate: 1 // 0 to disable + + // Enable callstats only for a percentage of users. + // This takes a value between 0 and 100 which determines the probability for + // the callstats to be enabled. + // callStatsThreshold: 5 // enable callstats for 5% of the users. + }, + + // Disables ICE/UDP by filtering out local and remote UDP candidates in + // signalling. + // webrtcIceUdpDisable: false, + + // Disables ICE/TCP by filtering out local and remote TCP candidates in + // signalling. + // webrtcIceTcpDisable: false, + + + // Media + // + + // Audio + + // Disable measuring of audio levels. + disableAudioLevels: $(if [ -n "${DISABLE_AUDIO_LEVELS}" ]; then printf "true"; else printf "false"; fi), + // audioLevelsInterval: 200, + + // Enabling this will run the lib-jitsi-meet no audio detection module which + // will notify the user if the current selected microphone has no audio + // input and will suggest another valid device if one is present. + enableNoAudioDetection: true, + + // Enabling this will run the lib-jitsi-meet noise detection module which will + // notify the user if there is noise, other than voice, coming from the current + // selected microphone. The purpose it to let the user know that the input could + // be potentially unpleasant for other meeting participants. + enableNoisyMicDetection: true, + + // Start the conference in audio only mode (no video is being received nor + // sent). + // startAudioOnly: false, + + // Every participant after the Nth will start audio muted. + // startAudioMuted: 10, + + // Start calls with audio muted. Unlike the option above, this one is only + // applied locally. FIXME: having these 2 options is confusing. + // startWithAudioMuted: false, + + // Enabling it (with #params) will disable local audio output of remote + // participants and to enable it back a reload is needed. + // startSilent: false + + // Sets the preferred target bitrate for the Opus audio codec by setting its + // 'maxaveragebitrate' parameter. Currently not available in p2p mode. + // Valid values are in the range 6000 to 510000 + // opusMaxAverageBitrate: 20000, + + // Enables redundancy for Opus + // enableOpusRed: false + + // Video + + // Sets the preferred resolution (height) for local video. Defaults to 720. + // resolution: 720, + + // How many participants while in the tile view mode, before the receiving video quality is reduced from HD to SD. + // Use -1 to disable. + // maxFullResolutionParticipants: 2, + + // w3c spec-compliant video constraints to use for video capture. Currently + // used by browsers that return true from lib-jitsi-meet's + // util#browser#usesNewGumFlow. The constraints are independent from + // this config's resolution value. Defaults to requesting an ideal + // resolution of 720p. + // constraints: { + // video: { + // height: { + // ideal: 720, + // max: 720, + // min: 240 + // } + // } + // }, +$(if [ -n "${VIDEO_CONSTRAINTS}" ]; then echo "${VIDEO_CONSTRAINTS},"; fi) + + // Enable / disable simulcast support. + // disableSimulcast: false, + + // Enable / disable layer suspension. If enabled, endpoints whose HD + // layers are not in use will be suspended (no longer sent) until they + // are requested again. + // enableLayerSuspension: false, + + // Every participant after the Nth will start video muted. + startVideoMuted: ${START_VIDEO_MUTED}, + + // Start calls with video muted. Unlike the option above, this one is only + // applied locally. FIXME: having these 2 options is confusing. + // startWithVideoMuted: false, + + // If set to true, prefer to use the H.264 video codec (if supported). + // Note that it's not recommended to do this because simulcast is not + // supported when using H.264. For 1-to-1 calls this setting is enabled by + // default and can be toggled in the p2p section. + // This option has been deprecated, use preferredCodec under videoQuality section instead. + // preferH264: true, + + // If set to true, disable H.264 video codec by stripping it out of the + // SDP. + // disableH264: false, + + // Desktop sharing + + // Optional desktop sharing frame rate options. Default value: min:5, max:5. + // desktopSharingFrameRate: { + // min: 5, + // max: 5 + // }, + + // Try to start calls with screen-sharing instead of camera video. + // startScreenSharing: false, + + // Recording + + // Whether to enable file recording or not. + // fileRecordingsEnabled: false, + // Enable the dropbox integration. + // dropbox: { + // appKey: '' // Specify your app key here. + // // A URL to redirect the user to, after authenticating + // // by default uses: + // // 'https://${JITSI_HOST}/static/oauth.html' + // redirectURI: + // 'https://${JITSI_HOST}/subfolder/static/oauth.html' + // }, + // When integrations like dropbox are enabled only that will be shown, + // by enabling fileRecordingsServiceEnabled, we show both the integrations + // and the generic recording service (its configuration and storage type + // depends on jibri configuration) + // fileRecordingsServiceEnabled: false, + // Whether to show the possibility to share file recording with other people + // (e.g. meeting participants), based on the actual implementation + // on the backend. + // fileRecordingsServiceSharingEnabled: false, + + // Whether to enable live streaming or not. + // liveStreamingEnabled: false, + + // Transcription (in interface_config, + // subtitles and buttons can be configured) + // transcribingEnabled: false, + + // Enables automatic turning on captions when recording is started + // autoCaptionOnRecord: false, + + // Misc + + // Default value for the channel "last N" attribute. -1 for unlimited. + channelLastN: ${CHANNEL_LAST_N}, + + // Provides a way to use different "last N" values based on the number of participants in the conference. + // The keys in an Object represent number of participants and the values are "last N" to be used when number of + // participants gets to or above the number. + // + // For the given example mapping, "last N" will be set to 20 as long as there are at least 5, but less than + // 29 participants in the call and it will be lowered to 15 when the 30th participant joins. The 'channelLastN' + // will be used as default until the first threshold is reached. + // + // lastNLimits: { + // 5: 20, + // 30: 15, + // 50: 10, + // 70: 5, + // 90: 2 + // }, + + // Specify the settings for video quality optimizations on the client. + // videoQuality: { + // // Provides a way to prevent a video codec from being negotiated on the JVB connection. The codec specified + // // here will be removed from the list of codecs present in the SDP answer generated by the client. If the + // // same codec is specified for both the disabled and preferred option, the disable settings will prevail. + // // Note that 'VP8' cannot be disabled since it's a mandatory codec, the setting will be ignored in this case. + // disabledCodec: 'H264', + // + // // Provides a way to set a preferred video codec for the JVB connection. If 'H264' is specified here, + // // simulcast will be automatically disabled since JVB doesn't support H264 simulcast yet. This will only + // // rearrange the the preference order of the codecs in the SDP answer generated by the browser only if the + // // preferred codec specified here is present. Please ensure that the JVB offers the specified codec for this + // // to take effect. + // preferredCodec: 'VP8', + // + // // Provides a way to configure the maximum bitrates that will be enforced on the simulcast streams for + // // video tracks. The keys in the object represent the type of the stream (LD, SD or HD) and the values + // // are the max.bitrates to be set on that particular type of stream. The actual send may vary based on + // // the available bandwidth calculated by the browser, but it will be capped by the values specified here. + // // This is currently not implemented on app based clients on mobile. + // maxBitratesVideo: { + // low: 200000, + // standard: 500000, + // high: 1500000 + // }, + // + // // The options can be used to override default thresholds of video thumbnail heights corresponding to + // // the video quality levels used in the application. At the time of this writing the allowed levels are: + // // 'low' - for the low quality level (180p at the time of this writing) + // // 'standard' - for the medium quality level (360p) + // // 'high' - for the high quality level (720p) + // // The keys should be positive numbers which represent the minimal thumbnail height for the quality level. + // // + // // With the default config value below the application will use 'low' quality until the thumbnails are + // // at least 360 pixels tall. If the thumbnail height reaches 720 pixels then the application will switch to + // // the high quality. + // minHeightForQualityLvl: { + // 360: 'standard, + // 720: 'high' + // } + // }, + + // // Options for the recording limit notification. + // recordingLimit: { + // + // // The recording limit in minutes. Note: This number appears in the notification text + // // but doesn't enforce the actual recording time limit. This should be configured in + // // jibri! + // limit: 60, + // + // // The name of the app with unlimited recordings. + // appName: 'Unlimited recordings APP', + // + // // The URL of the app with unlimited recordings. + // appURL: 'https://unlimited.recordings.app.com/' + // }, + + // Disables or enables RTX (RFC 4588) (defaults to false). + // disableRtx: false, + + // Disables or enables TCC (the default is in Jicofo and set to true) + // (draft-holmer-rmcat-transport-wide-cc-extensions-01). This setting + // affects congestion control, it practically enables send-side bandwidth + // estimations. + // enableTcc: true, + + // Disables or enables REMB (the default is in Jicofo and set to false) + // (draft-alvestrand-rmcat-remb-03). This setting affects congestion + // control, it practically enables recv-side bandwidth estimations. When + // both TCC and REMB are enabled, TCC takes precedence. When both are + // disabled, then bandwidth estimations are disabled. + // enableRemb: false, + + // Enables ICE restart logic in LJM and displays the page reload overlay on + // ICE failure. Current disabled by default because it's causing issues with + // signaling when Octo is enabled. Also when we do an "ICE restart"(which is + // not a real ICE restart), the client maintains the TCC sequence number + // counter, but the bridge resets it. The bridge sends media packets with + // TCC sequence numbers starting from 0. + // enableIceRestart: false, + + // Defines the minimum number of participants to start a call (the default + // is set in Jicofo and set to 2). + // minParticipants: 2, + + // Use TURN/UDP servers for the jitsi-videobridge connection (by default + // we filter out TURN/UDP because it is usually not needed since the + // bridge itself is reachable via UDP) + // useTurnUdp: false + + // Enables / disables a data communication channel with the Videobridge. + // Values can be 'datachannel', 'websocket', true (treat it as + // 'datachannel'), undefined (treat it as 'datachannel') and false (don't + // open any channel). + // openBridgeChannel: true, + openBridgeChannel: 'websocket', + + + // UI + // + + // Hides lobby button + // hideLobbyButton: false, + + // Require users to always specify a display name. + // requireDisplayName: true, + + // Whether to use a welcome page or not. In case it's false a random room + // will be joined when no room is specified. + enableWelcomePage: true, + + // Enabling the close page will ignore the welcome page redirection when + // a call is hangup. + // enableClosePage: false, + + // Disable hiding of remote thumbnails when in a 1-on-1 conference call. + // disable1On1Mode: false, + + // Default language for the user interface. + defaultLanguage: '${DEFAULT_LANGUAGE}', + + // If true all users without a token will be considered guests and all users + // with token will be considered non-guests. Only guests will be allowed to + // edit their profile. + enableUserRolesBasedOnToken: false, + + // Whether or not some features are checked based on token. + // enableFeaturesBasedOnToken: false, + + // Enable lock room for all moderators, even when userRolesBasedOnToken is enabled and participants are guests. + // lockRoomGuestEnabled: false, + + // When enabled the password used for locking a room is restricted to up to the number of digits specified + // roomPasswordNumberOfDigits: 10, + // default: roomPasswordNumberOfDigits: false, + + // Message to show the users. Example: 'The service will be down for + // maintenance at 01:00 AM GMT, + noticeMessage: '${NOTICE_MESSAGE}', + + // Enables calendar integration, depends on googleApiApplicationClientID + // and microsoftApiApplicationClientID + // enableCalendarIntegration: false, + + // When 'true', it shows an intermediate page before joining, where the user can configure their devices. + // prejoinPageEnabled: false, + + // If true, shows the unsafe room name warning label when a room name is + // deemed unsafe (due to the simplicity in the name) and a password is not + // set or the lobby is not enabled. + // enableInsecureRoomNameWarning: false, + + // Whether to automatically copy invitation URL after creating a room. + // Document should be focused for this option to work + // enableAutomaticUrlCopy: false, + + // Stats + // + + // Whether to enable stats collection or not in the TraceablePeerConnection. + // This can be useful for debugging purposes (post-processing/analysis of + // the webrtc stats) as it is done in the jitsi-meet-torture bandwidth + // estimation tests. + // gatherStats: false, + + // The interval at which PeerConnection.getStats() is called. Defaults to 10000 + // pcStatsInterval: 10000, + + // To enable sending statistics to callstats.io you must provide the + // Application ID and Secret. + // callStatsID: '', + // callStatsSecret: '', + + // Enables sending participants' display names to callstats + // enableDisplayNameInStats: false, + + // Enables sending participants' emails (if available) to callstats and other analytics + // enableEmailInStats: false, + + // Privacy + // + + // If third party requests are disabled, no other server will be contacted. + // This means avatars will be locally generated and callstats integration + // will not function. + disableThirdPartyRequests: $(if [ -z "${ENABLE_THIRD_PARTY_REQUESTS}" ]; then printf "true"; else printf "false"; fi), + + + // Peer-To-Peer mode: used (if enabled) when there are just 2 participants. + // + + p2p: { + // Enables peer to peer mode. When enabled the system will try to + // establish a direct connection when there are exactly 2 participants + // in the room. If that succeeds the conference will stop sending data + // through the JVB and use the peer to peer connection instead. When a + // 3rd participant joins the conference will be moved back to the JVB + // connection. + enabled: true, + + // The STUN servers that will be used in the peer to peer connections + stunServers: [ + + { urls: 'stun:${TURN_SERVER}:443' } + ] + + // Sets the ICE transport policy for the p2p connection. At the time + // of this writing the list of possible values are 'all' and 'relay', + // but that is subject to change in the future. The enum is defined in + // the WebRTC standard: + // https://www.w3.org/TR/webrtc/#rtcicetransportpolicy-enum. + // If not set, the effective value is 'all'. + // iceTransportPolicy: 'all', + + // If set to true, it will prefer to use H.264 for P2P calls (if H.264 + // is supported). This setting is deprecated, use preferredCodec instead. + // preferH264: true + + // Provides a way to set the video codec preference on the p2p connection. Acceptable + // codec values are 'VP8', 'VP9' and 'H264'. + // preferredCodec: 'H264', + + // If set to true, disable H.264 video codec by stripping it out of the + // SDP. This setting is deprecated, use disabledCodec instead. + // disableH264: false, + + // Provides a way to prevent a video codec from being negotiated on the p2p connection. + // disabledCodec: '', + + // How long we're going to wait, before going back to P2P after the 3rd + // participant has left the conference (to filter out page reload). + // backToP2PDelay: 5 + }, + + analytics: { + // The Google Analytics Tracking ID: + // googleAnalyticsTrackingId: 'your-tracking-id-UA-123456-1' + + // Matomo configuration: + // matomoEndpoint: 'https://your-matomo-endpoint/', + // matomoSiteID: '42', + + // The Amplitude APP Key: + // amplitudeAPPKey: '' + + // Configuration for the rtcstats server: + // By enabling rtcstats server every time a conference is joined the rtcstats + // module connects to the provided rtcstatsEndpoint and sends statistics regarding + // PeerConnection states along with getStats metrics polled at the specified + // interval. + // rtcstatsEnabled: true, + + // In order to enable rtcstats one needs to provide a endpoint url. + // rtcstatsEndpoint: wss://rtcstats-server-pilot.jitsi.net/, + + // The interval at which rtcstats will poll getStats, defaults to 1000ms. + // If the value is set to 0 getStats won't be polled and the rtcstats client + // will only send data related to RTCPeerConnection events. + // rtcstatsPolIInterval: 1000 + + // Array of script URLs to load as lib-jitsi-meet "analytics handlers". + // scriptURLs: [ + // "libs/analytics-ga.min.js", // google-analytics + // "https://example.com/my-custom-analytics.js" + // ], + }, + + // Logs that should go be passed through the 'log' event if a handler is defined for it + // apiLogLevels: ['warn', 'log', 'error', 'info', 'debug'], + + // Information about the jitsi-meet instance we are connecting to, including + // the user region as seen by the server. + deploymentInfo: { + // shard: "shard1", + // region: "europe", + // userRegion: "asia" + }, + + // Decides whether the start/stop recording audio notifications should play on record. + // disableRecordAudioNotification: false, + + // Information for the chrome extension banner + // chromeExtensionBanner: { + // // The chrome extension to be installed address + // url: 'https://chrome.google.com/webstore/detail/jitsi-meetings/kglhbbefdnlheedjiejgomgmfplipfeb', + + // // Extensions info which allows checking if they are installed or not + // chromeExtensionsInfo: [ + // { + // id: 'kglhbbefdnlheedjiejgomgmfplipfeb', + // path: 'jitsi-logo-48x48.png' + // } + // ] + // }, + + // Local Recording + // + + // localRecording: { + // Enables local recording. + // Additionally, 'localrecording' (all lowercase) needs to be added to + // TOOLBAR_BUTTONS in interface_config.js for the Local Recording + // button to show up on the toolbar. + // + // enabled: true, + // + + // The recording format, can be one of 'ogg', 'flac' or 'wav'. + // format: 'flac' + // + + // }, + + // Options related to end-to-end (participant to participant) ping. + // e2eping: { + // // The interval in milliseconds at which pings will be sent. + // // Defaults to 10000, set to <= 0 to disable. + // pingInterval: 10000, + // + // // The interval in milliseconds at which analytics events + // // with the measured RTT will be sent. Defaults to 60000, set + // // to <= 0 to disable. + // analyticsInterval: 60000, + // }, + + // If set, will attempt to use the provided video input device label when + // triggering a screenshare, instead of proceeding through the normal flow + // for obtaining a desktop stream. + // NOTE: This option is experimental and is currently intended for internal + // use only. + // _desktopSharingSourceDevice: 'sample-id-or-label', + + // If true, any checks to handoff to another application will be prevented + // and instead the app will continue to display in the current browser. + // disableDeepLinking: false, + + // A property to disable the right click context menu for localVideo + // the menu has option to flip the locally seen video for local presentations + // disableLocalVideoFlip: false, + + // Mainly privacy related settings + + // Disables all invite functions from the app (share, invite, dial out...etc) + // disableInviteFunctions: true, + + // Disables storing the room name to the recents list + // doNotStoreRoom: true, + + // Deployment specific URLs. + // deploymentUrls: { + // // If specified a 'Help' button will be displayed in the overflow menu with a link to the specified URL for + // // user documentation. + // userDocumentationURL: 'https://docs.example.com/video-meetings.html', + // // If specified a 'Download our apps' button will be displayed in the overflow menu with a link + // // to the specified URL for an app download page. + // downloadAppsUrl: 'https://docs.example.com/our-apps.html' + // }, + + // Options related to the remote participant menu. + // remoteVideoMenu: { + // // If set to true the 'Kick out' button will be disabled. + // disableKick: true + // }, + + // If set to true all muting operations of remote participants will be disabled. + // disableRemoteMute: true, + + /** + External API url used to receive branding specific information. + If there is no url set or there are missing fields, the defaults are applied. + None of the fields are mandatory and the response must have the shape: + { + // The hex value for the colour used as background + backgroundColor: '#fff', + // The url for the image used as background + backgroundImageUrl: 'https://example.com/background-img.png', + // The anchor url used when clicking the logo image + logoClickUrl: 'https://example-company.org', + // The url used for the image used as logo + logoImageUrl: 'https://example.com/logo-img.png' + } + */ + brandingDataUrl: "$(if [ -n "${BRANDING_JSON}" ]; then printf "/branding.json"; fi)", + + // The URL of the moderated rooms microservice, if available. If it + // is present, a link to the service will be rendered on the welcome page, + // otherwise the app doesn't render it. + // moderatedRoomServiceUrl: 'https://moderated.${JITSI_HOST}', + + // List of undocumented settings used in jitsi-meet + /** + _immediateReloadThreshold + debug + debugAudioLevels + deploymentInfo + dialInConfCodeUrl + dialInNumbersUrl + dialOutAuthUrl + dialOutCodesUrl + disableRemoteControl + displayJids + etherpad_base + externalConnectUrl + firefox_fake_device + googleApiApplicationClientID + iAmRecorder + iAmSipGateway + microsoftApiApplicationClientID + peopleSearchQueryTypes + peopleSearchUrl + requireDisplayName + tokenAuthUrl + */ + + /** + * This property can be used to alter the generated meeting invite links (in combination with a branding domain + * which is retrieved internally by jitsi meet) (e.g. https://meet.jit.si/someMeeting + * can become https://brandedDomain/roomAlias) + */ + // brandingRoomAlias: null, + + // List of undocumented settings used in lib-jitsi-meet + /** + _peerConnStatusOutOfLastNTimeout + _peerConnStatusRtcMuteTimeout + abTesting + avgRtpStatsN + callStatsConfIDNamespace + callStatsCustomScriptUrl + desktopSharingSources + disableAEC + disableAGC + disableAP + disableHPF + disableNS + enableLipSync + enableTalkWhileMuted + forceJVB121Ratio + hiddenDomain + ignoreStartMuted + nick + startBitrate + */ + + + // Allow all above example options to include a trailing comma and + // prevent fear when commenting out the last value. + makeJsonParserHappy: 'even if last key had a trailing comma' + + // no configuration value should follow this line. +}; + +/* eslint-enable no-unused-vars, no-var */ +EOF +)" diff --git a/type/__jitsi_meet_domain/files/config.js.sh.orig b/type/__jitsi_meet_domain/files/config.js.sh.orig new file mode 100644 index 0000000..da2bff5 --- /dev/null +++ b/type/__jitsi_meet_domain/files/config.js.sh.orig @@ -0,0 +1,694 @@ +/* eslint-disable no-unused-vars, no-var */ + +var config = { + // Connection + // + + hosts: { + // XMPP domain. + domain: 'jitsi-meet.example.org', + + // When using authentication, domain for guest users. + // anonymousdomain: 'guest.example.com', + + // Domain for authenticated users. Defaults to . + // authdomain: 'jitsi-meet.example.org', + + // Call control component (Jigasi). + // call_control: 'callcontrol.jitsi-meet.example.org', + + // Focus component domain. Defaults to focus.. + // focus: 'focus.jitsi-meet.example.org', + + // XMPP MUC domain. FIXME: use XEP-0030 to discover it. + muc: 'conference.jitsi-meet.example.org' + }, + + // BOSH URL. FIXME: use XEP-0156 to discover it. + bosh: '//jitsi-meet.example.org/http-bind', + + // Websocket URL + // websocket: 'wss://jitsi-meet.example.org/xmpp-websocket', + + // The name of client node advertised in XEP-0115 'c' stanza + clientNode: 'http://jitsi.org/jitsimeet', + + // The real JID of focus participant - can be overridden here + // Do not change username - FIXME: Make focus username configurable + // https://github.com/jitsi/jitsi-meet/issues/7376 + // focusUserJid: 'focus@auth.jitsi-meet.example.org', + + + // Testing / experimental features. + // + + testing: { + // Disables the End to End Encryption feature. Useful for debugging + // issues related to insertable streams. + // disableE2EE: false, + + // P2P test mode disables automatic switching to P2P when there are 2 + // participants in the conference. + p2pTestMode: false + + // Enables the test specific features consumed by jitsi-meet-torture + // testMode: false + + // Disables the auto-play behavior of *all* newly created video element. + // This is useful when the client runs on a host with limited resources. + // noAutoPlayVideo: false + + // Enable / disable 500 Kbps bitrate cap on desktop tracks. When enabled, + // simulcast is turned off for the desktop share. If presenter is turned + // on while screensharing is in progress, the max bitrate is automatically + // adjusted to 2.5 Mbps. This takes a value between 0 and 1 which determines + // the probability for this to be enabled. + // capScreenshareBitrate: 1 // 0 to disable + + // Enable callstats only for a percentage of users. + // This takes a value between 0 and 100 which determines the probability for + // the callstats to be enabled. + // callStatsThreshold: 5 // enable callstats for 5% of the users. + }, + + // Disables ICE/UDP by filtering out local and remote UDP candidates in + // signalling. + // webrtcIceUdpDisable: false, + + // Disables ICE/TCP by filtering out local and remote TCP candidates in + // signalling. + // webrtcIceTcpDisable: false, + + + // Media + // + + // Audio + + // Disable measuring of audio levels. + // disableAudioLevels: false, + // audioLevelsInterval: 200, + + // Enabling this will run the lib-jitsi-meet no audio detection module which + // will notify the user if the current selected microphone has no audio + // input and will suggest another valid device if one is present. + enableNoAudioDetection: true, + + // Enabling this will run the lib-jitsi-meet noise detection module which will + // notify the user if there is noise, other than voice, coming from the current + // selected microphone. The purpose it to let the user know that the input could + // be potentially unpleasant for other meeting participants. + enableNoisyMicDetection: true, + + // Start the conference in audio only mode (no video is being received nor + // sent). + // startAudioOnly: false, + + // Every participant after the Nth will start audio muted. + // startAudioMuted: 10, + + // Start calls with audio muted. Unlike the option above, this one is only + // applied locally. FIXME: having these 2 options is confusing. + // startWithAudioMuted: false, + + // Enabling it (with #params) will disable local audio output of remote + // participants and to enable it back a reload is needed. + // startSilent: false + + // Sets the preferred target bitrate for the Opus audio codec by setting its + // 'maxaveragebitrate' parameter. Currently not available in p2p mode. + // Valid values are in the range 6000 to 510000 + // opusMaxAverageBitrate: 20000, + + // Enables redundancy for Opus + // enableOpusRed: false + + // Video + + // Sets the preferred resolution (height) for local video. Defaults to 720. + // resolution: 720, + + // How many participants while in the tile view mode, before the receiving video quality is reduced from HD to SD. + // Use -1 to disable. + // maxFullResolutionParticipants: 2, + + // w3c spec-compliant video constraints to use for video capture. Currently + // used by browsers that return true from lib-jitsi-meet's + // util#browser#usesNewGumFlow. The constraints are independent from + // this config's resolution value. Defaults to requesting an ideal + // resolution of 720p. + // constraints: { + // video: { + // height: { + // ideal: 720, + // max: 720, + // min: 240 + // } + // } + // }, + + // Enable / disable simulcast support. + // disableSimulcast: false, + + // Enable / disable layer suspension. If enabled, endpoints whose HD + // layers are not in use will be suspended (no longer sent) until they + // are requested again. + // enableLayerSuspension: false, + + // Every participant after the Nth will start video muted. + // startVideoMuted: 10, + + // Start calls with video muted. Unlike the option above, this one is only + // applied locally. FIXME: having these 2 options is confusing. + // startWithVideoMuted: false, + + // If set to true, prefer to use the H.264 video codec (if supported). + // Note that it's not recommended to do this because simulcast is not + // supported when using H.264. For 1-to-1 calls this setting is enabled by + // default and can be toggled in the p2p section. + // This option has been deprecated, use preferredCodec under videoQuality section instead. + // preferH264: true, + + // If set to true, disable H.264 video codec by stripping it out of the + // SDP. + // disableH264: false, + + // Desktop sharing + + // Optional desktop sharing frame rate options. Default value: min:5, max:5. + // desktopSharingFrameRate: { + // min: 5, + // max: 5 + // }, + + // Try to start calls with screen-sharing instead of camera video. + // startScreenSharing: false, + + // Recording + + // Whether to enable file recording or not. + // fileRecordingsEnabled: false, + // Enable the dropbox integration. + // dropbox: { + // appKey: '' // Specify your app key here. + // // A URL to redirect the user to, after authenticating + // // by default uses: + // // 'https://jitsi-meet.example.org/static/oauth.html' + // redirectURI: + // 'https://jitsi-meet.example.org/subfolder/static/oauth.html' + // }, + // When integrations like dropbox are enabled only that will be shown, + // by enabling fileRecordingsServiceEnabled, we show both the integrations + // and the generic recording service (its configuration and storage type + // depends on jibri configuration) + // fileRecordingsServiceEnabled: false, + // Whether to show the possibility to share file recording with other people + // (e.g. meeting participants), based on the actual implementation + // on the backend. + // fileRecordingsServiceSharingEnabled: false, + + // Whether to enable live streaming or not. + // liveStreamingEnabled: false, + + // Transcription (in interface_config, + // subtitles and buttons can be configured) + // transcribingEnabled: false, + + // Enables automatic turning on captions when recording is started + // autoCaptionOnRecord: false, + + // Misc + + // Default value for the channel "last N" attribute. -1 for unlimited. + channelLastN: -1, + + // Provides a way to use different "last N" values based on the number of participants in the conference. + // The keys in an Object represent number of participants and the values are "last N" to be used when number of + // participants gets to or above the number. + // + // For the given example mapping, "last N" will be set to 20 as long as there are at least 5, but less than + // 29 participants in the call and it will be lowered to 15 when the 30th participant joins. The 'channelLastN' + // will be used as default until the first threshold is reached. + // + // lastNLimits: { + // 5: 20, + // 30: 15, + // 50: 10, + // 70: 5, + // 90: 2 + // }, + + // Specify the settings for video quality optimizations on the client. + // videoQuality: { + // // Provides a way to prevent a video codec from being negotiated on the JVB connection. The codec specified + // // here will be removed from the list of codecs present in the SDP answer generated by the client. If the + // // same codec is specified for both the disabled and preferred option, the disable settings will prevail. + // // Note that 'VP8' cannot be disabled since it's a mandatory codec, the setting will be ignored in this case. + // disabledCodec: 'H264', + // + // // Provides a way to set a preferred video codec for the JVB connection. If 'H264' is specified here, + // // simulcast will be automatically disabled since JVB doesn't support H264 simulcast yet. This will only + // // rearrange the the preference order of the codecs in the SDP answer generated by the browser only if the + // // preferred codec specified here is present. Please ensure that the JVB offers the specified codec for this + // // to take effect. + // preferredCodec: 'VP8', + // + // // Provides a way to configure the maximum bitrates that will be enforced on the simulcast streams for + // // video tracks. The keys in the object represent the type of the stream (LD, SD or HD) and the values + // // are the max.bitrates to be set on that particular type of stream. The actual send may vary based on + // // the available bandwidth calculated by the browser, but it will be capped by the values specified here. + // // This is currently not implemented on app based clients on mobile. + // maxBitratesVideo: { + // low: 200000, + // standard: 500000, + // high: 1500000 + // }, + // + // // The options can be used to override default thresholds of video thumbnail heights corresponding to + // // the video quality levels used in the application. At the time of this writing the allowed levels are: + // // 'low' - for the low quality level (180p at the time of this writing) + // // 'standard' - for the medium quality level (360p) + // // 'high' - for the high quality level (720p) + // // The keys should be positive numbers which represent the minimal thumbnail height for the quality level. + // // + // // With the default config value below the application will use 'low' quality until the thumbnails are + // // at least 360 pixels tall. If the thumbnail height reaches 720 pixels then the application will switch to + // // the high quality. + // minHeightForQualityLvl: { + // 360: 'standard, + // 720: 'high' + // } + // }, + + // // Options for the recording limit notification. + // recordingLimit: { + // + // // The recording limit in minutes. Note: This number appears in the notification text + // // but doesn't enforce the actual recording time limit. This should be configured in + // // jibri! + // limit: 60, + // + // // The name of the app with unlimited recordings. + // appName: 'Unlimited recordings APP', + // + // // The URL of the app with unlimited recordings. + // appURL: 'https://unlimited.recordings.app.com/' + // }, + + // Disables or enables RTX (RFC 4588) (defaults to false). + // disableRtx: false, + + // Disables or enables TCC (the default is in Jicofo and set to true) + // (draft-holmer-rmcat-transport-wide-cc-extensions-01). This setting + // affects congestion control, it practically enables send-side bandwidth + // estimations. + // enableTcc: true, + + // Disables or enables REMB (the default is in Jicofo and set to false) + // (draft-alvestrand-rmcat-remb-03). This setting affects congestion + // control, it practically enables recv-side bandwidth estimations. When + // both TCC and REMB are enabled, TCC takes precedence. When both are + // disabled, then bandwidth estimations are disabled. + // enableRemb: false, + + // Enables ICE restart logic in LJM and displays the page reload overlay on + // ICE failure. Current disabled by default because it's causing issues with + // signaling when Octo is enabled. Also when we do an "ICE restart"(which is + // not a real ICE restart), the client maintains the TCC sequence number + // counter, but the bridge resets it. The bridge sends media packets with + // TCC sequence numbers starting from 0. + // enableIceRestart: false, + + // Defines the minimum number of participants to start a call (the default + // is set in Jicofo and set to 2). + // minParticipants: 2, + + // Use TURN/UDP servers for the jitsi-videobridge connection (by default + // we filter out TURN/UDP because it is usually not needed since the + // bridge itself is reachable via UDP) + // useTurnUdp: false + + // Enables / disables a data communication channel with the Videobridge. + // Values can be 'datachannel', 'websocket', true (treat it as + // 'datachannel'), undefined (treat it as 'datachannel') and false (don't + // open any channel). + // openBridgeChannel: true, + openBridgeChannel: 'websocket', + + + // UI + // + + // Hides lobby button + // hideLobbyButton: false, + + // Require users to always specify a display name. + // requireDisplayName: true, + + // Whether to use a welcome page or not. In case it's false a random room + // will be joined when no room is specified. + enableWelcomePage: true, + + // Enabling the close page will ignore the welcome page redirection when + // a call is hangup. + // enableClosePage: false, + + // Disable hiding of remote thumbnails when in a 1-on-1 conference call. + // disable1On1Mode: false, + + // Default language for the user interface. + // defaultLanguage: 'en', + + // If true all users without a token will be considered guests and all users + // with token will be considered non-guests. Only guests will be allowed to + // edit their profile. + enableUserRolesBasedOnToken: false, + + // Whether or not some features are checked based on token. + // enableFeaturesBasedOnToken: false, + + // Enable lock room for all moderators, even when userRolesBasedOnToken is enabled and participants are guests. + // lockRoomGuestEnabled: false, + + // When enabled the password used for locking a room is restricted to up to the number of digits specified + // roomPasswordNumberOfDigits: 10, + // default: roomPasswordNumberOfDigits: false, + + // Message to show the users. Example: 'The service will be down for + // maintenance at 01:00 AM GMT, + // noticeMessage: '', + + // Enables calendar integration, depends on googleApiApplicationClientID + // and microsoftApiApplicationClientID + // enableCalendarIntegration: false, + + // When 'true', it shows an intermediate page before joining, where the user can configure their devices. + // prejoinPageEnabled: false, + + // If true, shows the unsafe room name warning label when a room name is + // deemed unsafe (due to the simplicity in the name) and a password is not + // set or the lobby is not enabled. + // enableInsecureRoomNameWarning: false, + + // Whether to automatically copy invitation URL after creating a room. + // Document should be focused for this option to work + // enableAutomaticUrlCopy: false, + + // Stats + // + + // Whether to enable stats collection or not in the TraceablePeerConnection. + // This can be useful for debugging purposes (post-processing/analysis of + // the webrtc stats) as it is done in the jitsi-meet-torture bandwidth + // estimation tests. + // gatherStats: false, + + // The interval at which PeerConnection.getStats() is called. Defaults to 10000 + // pcStatsInterval: 10000, + + // To enable sending statistics to callstats.io you must provide the + // Application ID and Secret. + // callStatsID: '', + // callStatsSecret: '', + + // Enables sending participants' display names to callstats + // enableDisplayNameInStats: false, + + // Enables sending participants' emails (if available) to callstats and other analytics + // enableEmailInStats: false, + + // Privacy + // + + // If third party requests are disabled, no other server will be contacted. + // This means avatars will be locally generated and callstats integration + // will not function. + // disableThirdPartyRequests: false, + + + // Peer-To-Peer mode: used (if enabled) when there are just 2 participants. + // + + p2p: { + // Enables peer to peer mode. When enabled the system will try to + // establish a direct connection when there are exactly 2 participants + // in the room. If that succeeds the conference will stop sending data + // through the JVB and use the peer to peer connection instead. When a + // 3rd participant joins the conference will be moved back to the JVB + // connection. + enabled: true, + + // The STUN servers that will be used in the peer to peer connections + stunServers: [ + + // { urls: 'stun:jitsi-meet.example.org:3478' }, + { urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' } + ] + + // Sets the ICE transport policy for the p2p connection. At the time + // of this writing the list of possible values are 'all' and 'relay', + // but that is subject to change in the future. The enum is defined in + // the WebRTC standard: + // https://www.w3.org/TR/webrtc/#rtcicetransportpolicy-enum. + // If not set, the effective value is 'all'. + // iceTransportPolicy: 'all', + + // If set to true, it will prefer to use H.264 for P2P calls (if H.264 + // is supported). This setting is deprecated, use preferredCodec instead. + // preferH264: true + + // Provides a way to set the video codec preference on the p2p connection. Acceptable + // codec values are 'VP8', 'VP9' and 'H264'. + // preferredCodec: 'H264', + + // If set to true, disable H.264 video codec by stripping it out of the + // SDP. This setting is deprecated, use disabledCodec instead. + // disableH264: false, + + // Provides a way to prevent a video codec from being negotiated on the p2p connection. + // disabledCodec: '', + + // How long we're going to wait, before going back to P2P after the 3rd + // participant has left the conference (to filter out page reload). + // backToP2PDelay: 5 + }, + + analytics: { + // The Google Analytics Tracking ID: + // googleAnalyticsTrackingId: 'your-tracking-id-UA-123456-1' + + // Matomo configuration: + // matomoEndpoint: 'https://your-matomo-endpoint/', + // matomoSiteID: '42', + + // The Amplitude APP Key: + // amplitudeAPPKey: '' + + // Configuration for the rtcstats server: + // By enabling rtcstats server every time a conference is joined the rtcstats + // module connects to the provided rtcstatsEndpoint and sends statistics regarding + // PeerConnection states along with getStats metrics polled at the specified + // interval. + // rtcstatsEnabled: true, + + // In order to enable rtcstats one needs to provide a endpoint url. + // rtcstatsEndpoint: wss://rtcstats-server-pilot.jitsi.net/, + + // The interval at which rtcstats will poll getStats, defaults to 1000ms. + // If the value is set to 0 getStats won't be polled and the rtcstats client + // will only send data related to RTCPeerConnection events. + // rtcstatsPolIInterval: 1000 + + // Array of script URLs to load as lib-jitsi-meet "analytics handlers". + // scriptURLs: [ + // "libs/analytics-ga.min.js", // google-analytics + // "https://example.com/my-custom-analytics.js" + // ], + }, + + // Logs that should go be passed through the 'log' event if a handler is defined for it + // apiLogLevels: ['warn', 'log', 'error', 'info', 'debug'], + + // Information about the jitsi-meet instance we are connecting to, including + // the user region as seen by the server. + deploymentInfo: { + // shard: "shard1", + // region: "europe", + // userRegion: "asia" + }, + + // Decides whether the start/stop recording audio notifications should play on record. + // disableRecordAudioNotification: false, + + // Information for the chrome extension banner + // chromeExtensionBanner: { + // // The chrome extension to be installed address + // url: 'https://chrome.google.com/webstore/detail/jitsi-meetings/kglhbbefdnlheedjiejgomgmfplipfeb', + + // // Extensions info which allows checking if they are installed or not + // chromeExtensionsInfo: [ + // { + // id: 'kglhbbefdnlheedjiejgomgmfplipfeb', + // path: 'jitsi-logo-48x48.png' + // } + // ] + // }, + + // Local Recording + // + + // localRecording: { + // Enables local recording. + // Additionally, 'localrecording' (all lowercase) needs to be added to + // TOOLBAR_BUTTONS in interface_config.js for the Local Recording + // button to show up on the toolbar. + // + // enabled: true, + // + + // The recording format, can be one of 'ogg', 'flac' or 'wav'. + // format: 'flac' + // + + // }, + + // Options related to end-to-end (participant to participant) ping. + // e2eping: { + // // The interval in milliseconds at which pings will be sent. + // // Defaults to 10000, set to <= 0 to disable. + // pingInterval: 10000, + // + // // The interval in milliseconds at which analytics events + // // with the measured RTT will be sent. Defaults to 60000, set + // // to <= 0 to disable. + // analyticsInterval: 60000, + // }, + + // If set, will attempt to use the provided video input device label when + // triggering a screenshare, instead of proceeding through the normal flow + // for obtaining a desktop stream. + // NOTE: This option is experimental and is currently intended for internal + // use only. + // _desktopSharingSourceDevice: 'sample-id-or-label', + + // If true, any checks to handoff to another application will be prevented + // and instead the app will continue to display in the current browser. + // disableDeepLinking: false, + + // A property to disable the right click context menu for localVideo + // the menu has option to flip the locally seen video for local presentations + // disableLocalVideoFlip: false, + + // Mainly privacy related settings + + // Disables all invite functions from the app (share, invite, dial out...etc) + // disableInviteFunctions: true, + + // Disables storing the room name to the recents list + // doNotStoreRoom: true, + + // Deployment specific URLs. + // deploymentUrls: { + // // If specified a 'Help' button will be displayed in the overflow menu with a link to the specified URL for + // // user documentation. + // userDocumentationURL: 'https://docs.example.com/video-meetings.html', + // // If specified a 'Download our apps' button will be displayed in the overflow menu with a link + // // to the specified URL for an app download page. + // downloadAppsUrl: 'https://docs.example.com/our-apps.html' + // }, + + // Options related to the remote participant menu. + // remoteVideoMenu: { + // // If set to true the 'Kick out' button will be disabled. + // disableKick: true + // }, + + // If set to true all muting operations of remote participants will be disabled. + // disableRemoteMute: true, + + /** + External API url used to receive branding specific information. + If there is no url set or there are missing fields, the defaults are applied. + None of the fields are mandatory and the response must have the shape: + { + // The hex value for the colour used as background + backgroundColor: '#fff', + // The url for the image used as background + backgroundImageUrl: 'https://example.com/background-img.png', + // The anchor url used when clicking the logo image + logoClickUrl: 'https://example-company.org', + // The url used for the image used as logo + logoImageUrl: 'https://example.com/logo-img.png' + } + */ + // brandingDataUrl: '', + + // The URL of the moderated rooms microservice, if available. If it + // is present, a link to the service will be rendered on the welcome page, + // otherwise the app doesn't render it. + // moderatedRoomServiceUrl: 'https://moderated.jitsi-meet.example.org', + + // List of undocumented settings used in jitsi-meet + /** + _immediateReloadThreshold + debug + debugAudioLevels + deploymentInfo + dialInConfCodeUrl + dialInNumbersUrl + dialOutAuthUrl + dialOutCodesUrl + disableRemoteControl + displayJids + etherpad_base + externalConnectUrl + firefox_fake_device + googleApiApplicationClientID + iAmRecorder + iAmSipGateway + microsoftApiApplicationClientID + peopleSearchQueryTypes + peopleSearchUrl + requireDisplayName + tokenAuthUrl + */ + + /** + * This property can be used to alter the generated meeting invite links (in combination with a branding domain + * which is retrieved internally by jitsi meet) (e.g. https://meet.jit.si/someMeeting + * can become https://brandedDomain/roomAlias) + */ + // brandingRoomAlias: null, + + // List of undocumented settings used in lib-jitsi-meet + /** + _peerConnStatusOutOfLastNTimeout + _peerConnStatusRtcMuteTimeout + abTesting + avgRtpStatsN + callStatsConfIDNamespace + callStatsCustomScriptUrl + desktopSharingSources + disableAEC + disableAGC + disableAP + disableHPF + disableNS + enableLipSync + enableTalkWhileMuted + forceJVB121Ratio + hiddenDomain + ignoreStartMuted + nick + startBitrate + */ + + + // Allow all above example options to include a trailing comma and + // prevent fear when commenting out the last value. + makeJsonParserHappy: 'even if last key had a trailing comma' + + // no configuration value should follow this line. +}; + +/* eslint-enable no-unused-vars, no-var */ diff --git a/type/__jitsi_meet_domain/files/nginx.sh b/type/__jitsi_meet_domain/files/nginx.sh new file mode 100644 index 0000000..bb300fd --- /dev/null +++ b/type/__jitsi_meet_domain/files/nginx.sh @@ -0,0 +1,156 @@ +#!/bin/sh -e + +# shellcheck disable=SC2034 # This is intended to be included +JITSI_NGINX_CONFIG="$(cat < + + +COPYING +------- +Copyright \(C) 2020 Evilham. diff --git a/type/__jitsi_meet_domain/manifest b/type/__jitsi_meet_domain/manifest new file mode 100755 index 0000000..40b07b0 --- /dev/null +++ b/type/__jitsi_meet_domain/manifest @@ -0,0 +1,90 @@ +#!/bin/sh -e + +os="$(cat "${__global}/explorer/os")" +case "${os}" in + devuan|debian) + ;; + *) + echo "Your OS '${os}' is currently not supported." > /dev/stderr + exit 1 + ;; +esac + +DOMAIN="${__object_id}" +ADMIN_EMAIL="$(cat "${__object}/parameter/admin-email")" +CHANNEL_LAST_N="$(cat "${__object}/parameter/channel-last-n")" +DEFAULT_LANGUAGE="$(cat "${__object}/parameter/default-language")" +NOTICE_MESSAGE="$(cat "${__object}/parameter/notice-message")" +START_VIDEO_MUTED="$(cat "${__object}/parameter/start-video-muted")" +TURN_SERVER="$(cat "${__object}/parameter/turn-server")" +VIDEO_CONSTRAINTS="$(cat "${__object}/parameter/video-constraints")" +BRANDING_INDEX="$(cat "${__object}/parameter/branding-index")" +BRANDING_JSON="$(cat "${__object}/parameter/branding-json")" +BRANDING_WATERMARK="$(cat "${__object}/parameter/branding-watermark")" + +if [ -f "${__object}/parameter/enable-third-party-requests" ]; then + ENABLE_THIRD_PARTY_REQUESTS="YES" +fi +if [ -f "${__object}/parameter/disable-audio-levels" ]; then + DISABLE_AUDIO_LEVELS="YES" +fi + +if [ -z "${TURN_SERVER}" ]; then + TURN_SERVER="${__target_host}" +fi +if [ -z "${JITSI_HOST}" ]; then + JITSI_HOST="${__target_host}" +fi + +# +# Deal with certbot +# +# use object id as domain +__letsencrypt_cert "${DOMAIN}" \ + --admin-email "${ADMIN_EMAIL}" \ + --automatic-renewal \ + --renew-hook "service nginx reload" \ + --webroot /usr/share/jitsi-meet + +# Create virtualhost for nginx +# shellcheck source=type/__jitsi_meet_domain/files/nginx.sh +. "${__type}/files/nginx.sh" # This defines JITSI_NGINX_CONFIG +require="__letsencrypt_cert/${DOMAIN}" __file \ + "/etc/nginx/sites-enabled/${DOMAIN}.conf" \ + --mode 0644 --source "-" <. +# +# Find aliases for a given user name and print the aliases (each one on a +# separate line) + +aliases_file=$("${__type_explorer:?}/aliases_file") +test -r "${aliases_file}" || exit 0 + +: "${__object_id:?}" # assert __object_id is set, because it is used in AWK + +awk -F ':[ \t]*' ' +function print_aliases(aliases, matches) { + # prints comma-separated aliases (one per line) + split(aliases, matches, /,[ \t]*/) + for (i in matches) { + gsub(/^[ \t]*|[ \t]*$/, "", matches[i]) + if (matches[i]) print matches[i] + } +} + +/^#/ { + # comment line (ignore) + select = 0; cont = 0 # comments terminate alias lists and continuations + next +} + +{ + # is this line a continuation line? + # (the prev. line ended in a backslash or the line starts with whitespace) + is_cont = /^[ \t]/ || cont + + # detect if the line is a line to be continued (ends with a backslash) + cont = /\\$/ + + # if it is, we drop the backslash from the line + if (cont) sub(/[ \t]*\\$/, "", $0) +} + +is_cont { + # if in the alias list of the "target" user, we also print these aliases. + if (select) print_aliases($0) + next +} + +$1 == ENVIRON["__object_id"] { + # "target" user -> print alias list + select = 1 + print_aliases($2) + next +} + +{ + # other user + select = 0 +} +' "${aliases_file}" diff --git a/type/__mail_alias/explorer/aliases_file b/type/__mail_alias/explorer/aliases_file new file mode 100755 index 0000000..7f09f88 --- /dev/null +++ b/type/__mail_alias/explorer/aliases_file @@ -0,0 +1,52 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) +# +# 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 . +# +# This explorer finds the aliases file to modify. + +found() { echo "$*"; exit 0; } + +check_file() { + if test -f "$1" + then + found "$1" + fi +} + +case $("${__explorer:?}/os") +in + (freebsd|openbsd|solaris) + check_file /etc/mail/aliases + + # default + found /etc/mail/aliases + ;; + (alpine|debian|devuan|ubuntu) + check_file /etc/aliases + + # default + found /etc/aliases + ;; + (*) + check_file /etc/mail/aliases + check_file /etc/aliases + + # default + found /etc/aliases + ;; +esac diff --git a/type/__mail_alias/files/update_aliases.awk b/type/__mail_alias/files/update_aliases.awk new file mode 100644 index 0000000..11a4c85 --- /dev/null +++ b/type/__mail_alias/files/update_aliases.awk @@ -0,0 +1,96 @@ +#!/usr/bin/awk -f +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# 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 . +# + +function getvalue(path, line) { + # Reads the first line of the file located at path and returns it. + getline line < path + close(path) + return line +} + +function sepafter(f, def, _) { + # finds the separator between field $f and $(f+1) + _ = substr($0, length($f)+1, index(substr($0, length($f)+1), $(f+1))-1) + return _ ? _ : def +} + +function write_aliases( line) { + if (aliases_written) return + + # print aliases line + printf "%s%s", ENVIRON["__object_id"], sepafter(1, ": ") + while ((getline line < aliases_should_file) > 0) { + if (aliases_written) printf ", " + printf "%s", line + aliases_written = 1 + } + printf "\n" + close(aliases_should_file) +} + +BEGIN { + FS = ":[ \t]*" + + parameter_dir = ENVIRON["__object"] "/parameter/" + + mode = (getvalue(parameter_dir "state") != "absent") + aliases_should_file = (parameter_dir "/alias") +} + +/^[ \t]*\#/ { + # comment line (leave alone) + select = 0; cont = 0 # comments terminate alias lists and continuations + print + next +} + +{ + # is this line a continuation line? + # (the prev. line ended in a backslash or the line starts with whitespace) + is_cont = /^[ \t]/ || cont + + # detect if the line is a line to be continued (ends with a backslash) + cont = /\\$/ +} + +is_cont { + # we only print the line if it has not been rewritten (select) + if (!select) print + next +} + +$1 == ENVIRON["__object_id"] { + # "target" user -> rewrite aliases list + select = 1 + if (mode) write_aliases() + next +} + +{ + # other user + select = 0 + print +} + +END { + # if the last line was an alias, the separator will be reused (looks better) + if (mode && !aliases_written) + write_aliases() +} diff --git a/type/__mail_alias/gencode-remote b/type/__mail_alias/gencode-remote new file mode 100755 index 0000000..4a8f889 --- /dev/null +++ b/type/__mail_alias/gencode-remote @@ -0,0 +1,87 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# 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 . +# + +quote() { printf "'%s'" "$(printf '%s' "$*" | sed -e "s/'/'\\\\''/g")"; } +drop_awk_comments() { quote "$(sed '/^[[:blank:]]*#.*$/d;/^$/d' "$@")"; } + +aliases_file=$(cat "${__object:?}/explorer/aliases_file") + +test -n "${aliases_file}" || { + echo 'Could not determine aliases file path.' >&2 + exit 1 +} + + +state_should=$(cat "${__object:?}/parameter/state") + +case ${state_should} +in + (present) + if cmp -s "${__object:?}/explorer/aliases" "${__object:?}/parameter/alias" + then + # all good! + exit 0 + fi + + test -s "${__object:?}/parameter/alias" || { + printf 'The --alias parameter is required if --state present.\n' >&2 + printf 'Use --state absent to remove all aliases.\n' >&2 + exit 1 + } + + if test -s "${__object:?}/explorer/aliases" + then + echo "update aliases" >>"${__messages_out:?}" + else + echo "add aliases" >>"${__messages_out:?}" + fi + ;; + (absent) + # nothing to do if no aliases found. + test -s "${__object:?}/explorer/aliases" || exit 0 + + echo "delete aliases" >>"${__messages_out:?}" + ;; + (*) + printf 'Invalid --state: %s.\n' "${state_should}" >&2 + printf 'Acceptable values are: present, absent.\n' >&2 + exit 1 +esac + +cat <$(quote "${aliases_file}.tmp") \ +|| { + rm -f $(quote "${aliases_file}.tmp") + echo 'Generating new aliases file failed!' >&2 + exit 1 +} + +if ! cmp -s $(quote "${aliases_file}") $(quote "${aliases_file}.tmp") +then + # aliases file was modified, replace: + cat $(quote "${aliases_file}.tmp") >$(quote "${aliases_file}") + + # then, run newaliases if present ("missing" on Alpine Linux because of typo) + command -v newaliases >/dev/null 2>&1 && newaliases || true +fi +rm -f $(quote "${aliases_file}.tmp") +EOF diff --git a/type/__mail_alias/man.rst b/type/__mail_alias/man.rst new file mode 100644 index 0000000..de40512 --- /dev/null +++ b/type/__mail_alias/man.rst @@ -0,0 +1,76 @@ +cdist-type__mail_alias(7) +========================= + +NAME +---- +cdist-type__mail_alias - Manage mail aliases. + + +DESCRIPTION +----------- +This cdist type allows you to configure mail aliases (/etc/aliases). + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +state + 'present' or 'absent', defaults to 'present' +alias + an alias, i.e. a mail address where mail for the user should be redirected + to. + This parameter can be specified multiple times to redirect to multiple + recipients. + If ``--state`` is ``present`` this parameter is required. + See `aliases(5)` for the different forms this parameter can take. + + +BOOLEAN PARAMETERS +------------------ +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Redirect root mail to a "real" email address + __mail_alias root --alias admin@example.com + + # Disable redirection of mail for joe + __mail_alias joe --state absent + + +BUGS +---- +- Quoted strings are not parsed by this type. As a result, aliases + containing ``,`` (commas) are treated incorrectly (they are treated as + separate aliases.) + Make sure that email addresses, file names, and pipe commands do not contain + commas. +- ``:include:`` directives in the aliases file are not evaluated by this type. + They are treated like a regular alias, the values of the included file are + not expanded. + + +SEE ALSO +-------- +:strong:`aliases`\ (5) + + +AUTHORS +------- +Dennis Camera + + +COPYING +------- +Copyright \(C) 2020 Dennis Camera. 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/type/__mail_alias/nonparallel b/type/__mail_alias/nonparallel new file mode 100644 index 0000000..e69de29 diff --git a/type/__mail_alias/parameter/default/state b/type/__mail_alias/parameter/default/state new file mode 100644 index 0000000..e7f6134 --- /dev/null +++ b/type/__mail_alias/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/type/__mail_alias/parameter/optional b/type/__mail_alias/parameter/optional new file mode 100644 index 0000000..ff72b5c --- /dev/null +++ b/type/__mail_alias/parameter/optional @@ -0,0 +1 @@ +state diff --git a/type/__mail_alias/parameter/optional_multiple b/type/__mail_alias/parameter/optional_multiple new file mode 100644 index 0000000..d077ed8 --- /dev/null +++ b/type/__mail_alias/parameter/optional_multiple @@ -0,0 +1 @@ +alias diff --git a/type/__matrix_element/files/config.json.sh b/type/__matrix_element/files/config.json.sh new file mode 100755 index 0000000..9791f38 --- /dev/null +++ b/type/__matrix_element/files/config.json.sh @@ -0,0 +1,90 @@ +#!/bin/sh +# +# Upstream configuration guide/documentation: +# https://github.com/vector-im/riot-web/blob/develop/docs/config.md + +generate_embedded_pages () { + if [ "$EMBED_HOMEPAGE" != "" ]; then + cat << EOF + "embeddedPages": { + "homeUrl": "home.html" + }, +EOF + fi +} + +generate_jitsi_config () { + if [ "$JITSI_DOMAIN" != "" ]; then + cat << EOF + "jitsi": { + "preferredDomain": "$JITSI_DOMAIN" + }, +EOF + fi +} + +generate_branding () { + echo '"branding": {' + + if [ "$BRANDING_AUTH_HEADER_LOGO_URL" != "" ]; then + cat << EOF + "authHeaderLogoUrl": "$BRANDING_AUTH_HEADER_LOGO_URL", +EOF + fi + + if [ "$BRANDING_AUTH_FOOTER_LINKS" != "" ]; then + cat << EOF + "authFooterLinks": "$BRANDING_AUTH_FOOTER_LINKS", +EOF + fi + + cat << EOF + "welcomeBackgroundUrl": "themes/element/img/backgrounds/lake.jpg" +EOF + echo '},' +} + +cat << EOF +{ + "default_server_config": { + "m.homeserver": { + "base_url": "$DEFAULT_SERVER_URL", + "server_name": "$DEFAULT_SERVER_NAME" + }, + "m.identity_server": { + "base_url": "https://vector.im" + } + }, + "brand": "$BRAND", + $(generate_branding) + "defaultCountryCode": "$DEFAULT_COUNTRY_CODE", + "integrations_ui_url": "https://scalar.vector.im/", + "integrations_rest_url": "https://scalar.vector.im/api", + "integrations_widgets_urls": [ + "https://scalar.vector.im/_matrix/integrations/v1", + "https://scalar.vector.im/api", + "https://scalar-staging.vector.im/_matrix/integrations/v1", + "https://scalar-staging.vector.im/api", + "https://scalar-staging.riot.im/scalar/api" + ], + "bug_report_endpoint_url": "https://riot.im/bugreports/submit", + "roomDirectory": { + "servers": [ + $ROOM_DIRECTORY_SERVERS + ] + }, + "disable_custom_urls": "$DISABLE_CUSTOM_URLS", + $(generate_embedded_pages) + $(generate_jitsi_config) + "terms_and_conditions_links": [ + { + "url": "$PRIVACY_POLICY_URL", + "text": "Privacy Policy" + }, + { + "url": "$COOKIE_POLICY_URL", + "text": "Cookie Policy" + } + ] +} +EOF diff --git a/type/__matrix_element/gencode-remote b/type/__matrix_element/gencode-remote new file mode 100755 index 0000000..ff3bbaa --- /dev/null +++ b/type/__matrix_element/gencode-remote @@ -0,0 +1,95 @@ +#!/bin/sh -e +# +# 2019 Timothée Floure (timothee.floure@ungleich.ch) +# +# 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 . +# + +# Function to compare version strings. Returns success (0) if the version +# given by stdin is higher than the version provided by the argument. +# +# Taken from the cdist core type __sensible_editor. +version_ge() { + awk -F '[^0-9.]' -v target="${1:?}" ' + function max(x, y) { return x > y ? x : y; } + BEGIN { + getline; + nx = split($1, x, "."); + ny = split(target, y, "."); + for (i = 1; i <= max(nx, ny); ++i) { + diff = int(x[i]) - int(y[i]); + if (diff < 0) exit 1; + else if (diff > 0) exit 0; + else continue; + } + }' +} + + +VERSION=$(cat "$__object/parameter/version") +INSTALL_DIR=$(cat "$__object/parameter/install_dir") +OWNER=$(cat "$__object/parameter/owner") + +# tarball name changed due to application renaming +if echo "$VERSION" | version_ge 1.7.14; then + src="element-v$VERSION" +else + src="riot-v$VERSION" +fi +archive="$src.tar.gz" +url="https://github.com/vector-im/riot-web/releases/download/v$VERSION/$archive" + +# tar and curl are installed by the __matrix-riot manifest. mktemp is usually +# provided by coreutils and assumed installed. +cat << EOF +set -e + +# Ensure that coreutils is installed. +if [ ! -x \$(which mktemp) ]; then + echo "mktemp is not available on the remote host." >&2 + exit 1 +fi + +# Create temporary working directory. +tmpdir=\$(mktemp -d) +custom_files_dir="\$tmpdir/custom_files" +cd \$tmpdir + +# Download and extract sources. +curl -L '$url' > $archive +tar xf $archive + +# Backup files deployed by __matrix_element. +mkdir -p \$custom_files_dir +for file in $INSTALL_DIR/cdist/*; do + cp "\$file" "\$custom_files_dir" +done + +# Deploy sources and restore configuration. +rm -r '$INSTALL_DIR' +mv '$src' '$INSTALL_DIR' + +for file in \$custom_files_dir/*; do + cp "\$file" '$INSTALL_DIR' +done + +# Chown deployed files to requested owner. +chown -R '$OWNER' '$INSTALL_DIR' + +# Remove temporary working directory. +cd / +rm -r \$tmpdir +EOF diff --git a/type/__matrix_element/man.rst b/type/__matrix_element/man.rst new file mode 100644 index 0000000..05f0685 --- /dev/null +++ b/type/__matrix_element/man.rst @@ -0,0 +1,87 @@ +cdist-type__matrix_element(7) +============================= + +NAME +---- +cdist-type__matrix_element - Install and configure Element, a web Matrix client. + + +DESCRIPTION +----------- +This type install and configure the Element web client. + + +REQUIRED PARAMETERS +------------------- +install_dir + Root directory of Element's static files. + +version + Release of Element to install. + +OPTIONAL PARAMETERS +------------------- +default_server_name + Name of matrix homeserver to connect to, defaults to 'matrix.org'. + +default_server_url + URL of matrix homeserver to connect to, defaults to 'https://matrix-client.matrix.org'. + +owner + Owner of the deployed files, passed to `chown`. Defaults to 'root'. + +brand + Web UI branding, defaults to 'Element'. + +default_country_code + ISO 3166 alpha2 country code to use when showing country selectors, such as + phone number inputs. Defaults to GB. + +privacy_policy_url + Defaults to 'https://element.io/privacy'. + +cookie_policy_url + Defaults to 'https://matrix.org/docs/guides/element_im_cookie_policy'. + +jitsi_domain + Domain name of preferred Jitsi instance (default is jitsi.element.im). This is + used whenever a user clicks on the voice/video call buttons. + +homepage + Path to custom homepage, displayed once logged in. + +welcomepage + Path to custom welcome (= login) page. + +custom_asset + Serve a file a the top-level directory (e.g. /my-custom-logo.svg). Can be specified multiple times. + +BOOLEAN PARAMETERS +------------------- +disable_custom_urls + Disallow the user to change the default homeserver when signing up or logging in. + +EXAMPLES +-------- + +.. code-block:: sh + + __matrix_element my-element --install_dir /var/www/element-web --version 1.5.6 + + +SEE ALSO +-------- +- `cdist-type__matrix_synapse(7) `_ + + +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/type/__matrix_element/manifest b/type/__matrix_element/manifest new file mode 100755 index 0000000..544bd96 --- /dev/null +++ b/type/__matrix_element/manifest @@ -0,0 +1,106 @@ +#!/bin/sh -e +# +# 2019 Timothée Floure (timothee.floure@ungleich.ch) +# +# 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 . + +# Ignore "Declare and assign separately to avoid masking return values. [SC2155]" +# => not relevant for the type arguments. +# shellcheck disable=SC2155 + +INSTALL_DIR=$(cat "$__object/parameter/install_dir") + +export DEFAULT_SERVER_NAME=$(cat "$__object/parameter/default_server_name") +export DEFAULT_SERVER_URL=$(cat "$__object/parameter/default_server_url") +export BRAND=$(cat "$__object/parameter/brand") +export DEFAULT_COUNTRY_CODE=$(cat "$__object/parameter/default_country_code") +export ROOM_DIRECTORY_SERVERS=$(cat "$__object/parameter/room_directory_servers") +export PRIVACY_POLICY_URL=$(cat "$__object/parameter/privacy_policy_url") +export COOKIE_POLICY_URL=$(cat "$__object/parameter/cookie_policy_url") + +if [ -f "$__object/parameter/jitsi_domain" ]; then + export JITSI_DOMAIN=$(cat "$__object/parameter/jitsi_domain") +fi + +if [ -f "$__object/parameter/branding_auth_header_logo_url" ]; then + export BRANDING_AUTH_HEADER_LOGO_URL=$(cat "$__object/parameter/branding_auth_header_logo_url") +fi + +if [ -f "$__object/parameter/branding_auth_footer_links" ]; then + export BRANDING_AUTH_FOOTER_LINKS=$(cat "$__object/parameter/branding_auth_footer_links") +fi + +if [ -f "$__object/parameter/homepage" ]; then + export EMBED_HOMEPAGE=1 + homepage=$(cat "$__object/parameter/homepage") +fi + +if [ -f "$__object/parameter/welcomepage" ]; then + export EMBED_WELCOMEPAGE=1 + welcomepage=$(cat "$__object/parameter/welcomepage") +fi + +if [ -f "$__object/parameter/custom_asset" ]; then + "$__object/parameter/custom_asset" | while IFS= read -r file; do + require="__directory/$INSTALL_DIR/cdist" __file "$INSTALL_DIR/cdist/$(basename "$file")" \ + --source "$file" \ + --mode 0664 \ + --state present + done +fi + +if [ -f "$__object/parameter/disable_custom_urls" ]; then + export DISABLE_CUSTOM_URLS='true' +else + export DISABLE_CUSTOM_URLS='false' +fi + +# Owner of the uploaded files. +owner=$(cat "$__object/parameter/owner") + +# Ensure that curl and tar are installed, as they will be required by the +# gencode-remote script. +__package curl --state present +__package tar --state present + +# Generate and deploy configuration file. +mkdir -p "$__object/files" +"$__type/files/config.json.sh" > "$__object/files/config.json" + +# Install the config.json configuration file. The application's sources are +# downloaded and deployed by gencode-remote. +__directory "$INSTALL_DIR/cdist" \ + --owner "$owner" --mode 0755 --parents \ + --state present + +require="__directory/$INSTALL_DIR/cdist" __file "$INSTALL_DIR/cdist/config.json" \ + --source "$__object/files/config.json" \ + --mode 0664 \ + --state present + +if [ $EMBED_HOMEPAGE ]; then + require="__directory/$INSTALL_DIR/cdist" __file "$INSTALL_DIR/cdist/home.html" \ + --source "$homepage" \ + --mode 0664 \ + --state present +fi + +if [ $EMBED_WELCOMEPAGE ]; then + require="__directory/$INSTALL_DIR/cdist" __file "$INSTALL_DIR/cdist/welcome.html" \ + --source "$welcomepage" \ + --mode 0664 \ + --state present +fi diff --git a/type/__matrix_element/parameter/boolean b/type/__matrix_element/parameter/boolean new file mode 100644 index 0000000..4d77768 --- /dev/null +++ b/type/__matrix_element/parameter/boolean @@ -0,0 +1 @@ +disable_custom_urls diff --git a/type/__matrix_element/parameter/default/brand b/type/__matrix_element/parameter/default/brand new file mode 100644 index 0000000..907f907 --- /dev/null +++ b/type/__matrix_element/parameter/default/brand @@ -0,0 +1 @@ +Element diff --git a/type/__matrix_element/parameter/default/cookie_policy_url b/type/__matrix_element/parameter/default/cookie_policy_url new file mode 100644 index 0000000..04e9c2b --- /dev/null +++ b/type/__matrix_element/parameter/default/cookie_policy_url @@ -0,0 +1 @@ +https://matrix.org/docs/guides/riot_im_cookie_policy diff --git a/type/__matrix_element/parameter/default/default_country_code b/type/__matrix_element/parameter/default/default_country_code new file mode 100644 index 0000000..30ac4a3 --- /dev/null +++ b/type/__matrix_element/parameter/default/default_country_code @@ -0,0 +1 @@ +GB diff --git a/type/__matrix_element/parameter/default/default_server_name b/type/__matrix_element/parameter/default/default_server_name new file mode 100644 index 0000000..5528ffd --- /dev/null +++ b/type/__matrix_element/parameter/default/default_server_name @@ -0,0 +1 @@ +matrix.org diff --git a/type/__matrix_element/parameter/default/default_server_url b/type/__matrix_element/parameter/default/default_server_url new file mode 100644 index 0000000..2cb9227 --- /dev/null +++ b/type/__matrix_element/parameter/default/default_server_url @@ -0,0 +1 @@ +https://matrix-client.matrix.org diff --git a/type/__matrix_element/parameter/default/owner b/type/__matrix_element/parameter/default/owner new file mode 100644 index 0000000..d8649da --- /dev/null +++ b/type/__matrix_element/parameter/default/owner @@ -0,0 +1 @@ +root diff --git a/type/__matrix_element/parameter/default/privacy_policy_url b/type/__matrix_element/parameter/default/privacy_policy_url new file mode 100644 index 0000000..37fa4bc --- /dev/null +++ b/type/__matrix_element/parameter/default/privacy_policy_url @@ -0,0 +1 @@ +https://element.io/privacy diff --git a/type/__matrix_element/parameter/default/room_directory_servers b/type/__matrix_element/parameter/default/room_directory_servers new file mode 100644 index 0000000..4ea73ad --- /dev/null +++ b/type/__matrix_element/parameter/default/room_directory_servers @@ -0,0 +1 @@ +"matrix.org" diff --git a/type/__matrix_element/parameter/optional b/type/__matrix_element/parameter/optional new file mode 100644 index 0000000..21a2faf --- /dev/null +++ b/type/__matrix_element/parameter/optional @@ -0,0 +1,13 @@ +default_server_url +default_server_name +brand +default_country_code +privacy_policy_url +cookie_policy_url +room_directory_servers +owner +homepage +welcomepage +jitsi_domain +branding_auth_header_logo_url +branding_auth_footer_links diff --git a/type/__matrix_element/parameter/optional_multiple b/type/__matrix_element/parameter/optional_multiple new file mode 100644 index 0000000..4c2ca54 --- /dev/null +++ b/type/__matrix_element/parameter/optional_multiple @@ -0,0 +1 @@ +custom_asset diff --git a/type/__matrix_element/parameter/required b/type/__matrix_element/parameter/required new file mode 100644 index 0000000..a76477e --- /dev/null +++ b/type/__matrix_element/parameter/required @@ -0,0 +1,2 @@ +version +install_dir diff --git a/type/__matterbridge/files/matterbridge.service.sh b/type/__matterbridge/files/matterbridge.service.sh new file mode 100755 index 0000000..9dbd1cb --- /dev/null +++ b/type/__matterbridge/files/matterbridge.service.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +cat <`_ + + +AUTHORS +------- +Timothée Floure + + +COPYING +------- +Copyright \(C) 2020 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/type/__matterbridge/manifest b/type/__matterbridge/manifest new file mode 100755 index 0000000..ef02112 --- /dev/null +++ b/type/__matterbridge/manifest @@ -0,0 +1,98 @@ +#!/bin/sh -e +# +# 2020 Timothée Floure (timothee.floure@ungleich.ch) +# +# 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 . +# + +os=$(cat "$__global/explorer/os") +case "$os" in + debian) + # This type assume systemd for service installation. + ;; + *) + printf "Your operating system (%s) is currently not supported by this type (%s)\n" "$os" "${__type##*/}" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# Required parameters. +VERSION=$(cat "$__object/parameter/version") +if [ -f "$__object/parameter/config" ]; then + CONFIG="$(cat "$__object/parameter/config")" + if [ "$CONFIG" = "-" ]; then + CONFIG=$(cat "$__object/stdin") + fi +fi + +# Hardcoded values used in templates. +export BINARY_PATH=/usr/local/bin/matterbridge +export CONFIG_PATH=/etc/matterbridge/matterbridge.toml +export USER=matterbridge +export GROUP=$USER + +# Internal variables. +artefact="matterbridge-$VERSION-linux-64bit" +checksum_file="checksums.txt" +release_download_url=https://github.com/42wim/matterbridge/releases/download +binary_url="$release_download_url/v$VERSION/$artefact" +checksum_file_url="$release_download_url/v$VERSION/$checksum_file" +config_dir=$(dirname $CONFIG_PATH) +systemd_unit_path='/etc/systemd/system/matterbridge.service' + +# Check if curl is available. +if ! command -v curl; then + echo "curl is required for this type, but could not be found. Exiting." >&2 + exit 1 +fi + +# Initialize working directory. +mkdir -p "$__object/files" + +# Download and check matterbridge binary. +curl -L "$binary_url" -o "$__object/files/$artefact" +curl -Ls "$checksum_file_url" | grep "$artefact" > "$__object/files/$checksum_file" +if ! (cd "$__object/files"; sha256sum --check $checksum_file); then + echo "Matterbridge binary checksum failed." >&2 + exit 1 +fi + +# Create service user. +__user $USER --home "/var/lib/$USER" + +# Deploy matterbridge binary. +require="__user/$USER" __file "$BINARY_PATH" \ + --source "$__object/files/$artefact" \ + --owner "$USER" --mode 755 + +# Generate and deploy configuration file. +"$__type/files/matterbridge.service.sh" > "$__object/files/matterbridge.service" + +require="__user/$USER" __directory "$config_dir" \ + --owner "$USER" --mode 0755 --parents \ + +require="__directory/$config_dir" __file "$CONFIG_PATH" \ + --owner "$USER" \ + --mode 0640 \ + --source "$CONFIG" + +__file "$systemd_unit_path" \ + --source "$__object/files/matterbridge.service" + +# Deal with init system. +require="__file/$systemd_unit_path" __start_on_boot matterbridge +require="__file/$BINARY_PATH __file/$CONFIG_PATH __file/$systemd_unit_path" __service matterbridge --action restart diff --git a/type/__matterbridge/parameter/required b/type/__matterbridge/parameter/required new file mode 100644 index 0000000..ed5d8b3 --- /dev/null +++ b/type/__matterbridge/parameter/required @@ -0,0 +1,2 @@ +version +config diff --git a/type/__matterbridge/singleton b/type/__matterbridge/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__netbox/explorer/secretkey b/type/__netbox/explorer/secretkey new file mode 100755 index 0000000..7cce279 --- /dev/null +++ b/type/__netbox/explorer/secretkey @@ -0,0 +1,8 @@ +#!/bin/sh -e + +# Explorer will output the key if he exists. + +secretkey="/opt/netbox/cdist/secretkey" +if [ -f "$secretkey" ]; then + cat "$secretkey" +fi diff --git a/type/__netbox/explorer/version b/type/__netbox/explorer/version new file mode 100755 index 0000000..ee3dde8 --- /dev/null +++ b/type/__netbox/explorer/version @@ -0,0 +1,5 @@ +#!/bin/sh -e + +# output version if exist +version_path="/opt/netbox/cdist/version" +if [ -f "$version_path" ]; then cat "$version_path"; fi diff --git a/type/__netbox/files/configuration.py.sh b/type/__netbox/files/configuration.py.sh new file mode 100755 index 0000000..31ebd05 --- /dev/null +++ b/type/__netbox/files/configuration.py.sh @@ -0,0 +1,319 @@ +#!/bin/sh + +cat << EOF +######################### +# # +# Required settings # +# # +######################### + +# This is a list of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox will not permit write +# access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. +# +# Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local'] +ALLOWED_HOSTS = [$ALLOWED_HOSTS ] + +# PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: +# https://docs.djangoproject.com/en/stable/ref/settings/#databases +DATABASE = { + 'NAME': '$DATABASE_NAME', # Database name + 'USER': '$DATABASE_USER', # PostgreSQL username + 'PASSWORD': '$DATABASE_PASSWORD', # PostgreSQL password + 'HOST': '$DATABASE_HOST', # Database server + 'PORT': '$DATABASE_PORT', # Database port (leave blank for default) + 'CONN_MAX_AGE': 300, # Max database connection age +} + +# Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate +# configuration exists for each. Full connection details are required in both sections, and it is strongly recommended +# to use two separate database IDs. +REDIS = { + 'tasks': { + 'HOST': '$REDIS_HOST', + 'PORT': $REDIS_PORT, + # Comment out \`HOST\` and \`PORT\` lines and uncomment the following if using Redis Sentinel + # 'SENTINELS': [('mysentinel.redis.example.com', 6379)], + # 'SENTINEL_SERVICE': 'netbox', + 'PASSWORD': '$REDIS_PASSWORD', + 'DATABASE': $((REDIS_DBID_OFFSET + 0)), + 'SSL': $REDIS_SSL, + }, + 'caching': { + 'HOST': '$REDIS_HOST', + 'PORT': $REDIS_PORT, + # Comment out \`HOST\` and \`PORT\` lines and uncomment the following if using Redis Sentinel + # 'SENTINELS': [('mysentinel.redis.example.com', 6379)], + # 'SENTINEL_SERVICE': 'netbox', + 'PASSWORD': '$REDIS_PASSWORD', + 'DATABASE': $((REDIS_DBID_OFFSET + 1)), + 'SSL': $REDIS_SSL, + } +} +RQ_DEFAULT_TIMEOUT = 300 + +# This key is used for secure generation of random numbers and strings. It must never be exposed outside of this file. +# For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and +# symbols. NetBox will not run without this defined. For more information, see +# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY +SECRET_KEY = '$SECRET_KEY' + + +######################### +# # +# Optional settings # +# # +######################### + +# Specify one or more name and email address tuples representing NetBox administrators. These people will be notified of +# application errors (assuming correct email settings are provided). +ADMINS = [ + # ['John Doe', 'jdoe@example.com'], +] + +# URL schemes that are allowed within links in NetBox +ALLOWED_URL_SCHEMES = ( + 'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc', 'xmpp', +) + +# Optionally display a persistent banner at the top and/or bottom of every page. HTML is allowed. To display the same +# content in both banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP. +BANNER_TOP = '' +BANNER_BOTTOM = '' + +# Text to include on the login page above the login form. HTML is allowed. +BANNER_LOGIN = '' + +# Base URL path if accessing NetBox within a directory. For example, if installed at http://example.com/netbox/, set: +# BASE_PATH = 'netbox/' +BASE_PATH = '$BASEPATH' + +# Cache timeout in seconds. Set to 0 to dissable caching. Defaults to 900 (15 minutes) +CACHE_TIMEOUT = 900 + +# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90) +CHANGELOG_RETENTION = 90 + +# API Cross-Origin Resource Sharing (CORS) settings. If CORS_ORIGIN_ALLOW_ALL is set to True, all origins will be +# allowed. Otherwise, define a list of allowed origins using either CORS_ORIGIN_WHITELIST or +# CORS_ORIGIN_REGEX_WHITELIST. For more information, see https://github.com/ottoyiu/django-cors-headers +CORS_ORIGIN_ALLOW_ALL = False +CORS_ORIGIN_WHITELIST = [ + # 'https://hostname.example.com', +] +CORS_ORIGIN_REGEX_WHITELIST = [ + # r'^(https?://)?(\w+\.)?example\.com$', +] + +# Set to True to enable server debugging. WARNING: Debugging introduces a substantial performance penalty and may reveal +# sensitive information about your installation. Only enable debugging while performing testing. Never enable debugging +# on a production system. +DEBUG = False + +# Email settings +EMAIL = { + 'SERVER': '$SMTP_HOST', + 'PORT': $SMTP_PORT, + 'USERNAME': '$SMTP_USER', + 'PASSWORD': '$SMTP_PASSWORD', + 'USE_SSL': $SMTP_USE_SSL, + 'USE_TLS': $SMTP_USE_TLS, + 'TIMEOUT': 10, # seconds + 'FROM_EMAIL': '$SMTP_FROM_EMAIL', +} + +# Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce unique IP space within the global table +# (all prefixes and IP addresses not assigned to a VRF), set ENFORCE_GLOBAL_UNIQUE to True. +ENFORCE_GLOBAL_UNIQUE = False + +# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and +# by anonymous users. List models in the form \`.\`. Add '*' to this list to exempt all models. +EXEMPT_VIEW_PERMISSIONS = [ + # 'dcim.site', + # 'dcim.region', + # 'ipam.prefix', +] + +EOF + +if [ "$HTTP_PROXY" != "" ] || [ "$HTTPS_PROXY" != "" ]; then + cat << EOF +# HTTP proxies NetBox should use when sending outbound HTTP requests (e.g. for webhooks). +HTTP_PROXIES = { +EOF + if [ "$HTTP_PROXY" != "" ]; then + cat << EOF + 'http': '$HTTP_PROXY', +EOF + fi + if [ "$HTTPS_PROXY" != "" ]; then + cat << EOF + 'https': '$HTTPS_PROXY', +EOF + fi + cat << EOF +} +EOF +fi + +cat << EOF +# IP addresses recognized as internal to the system. The debugging toolbar will be available only to clients accessing +# NetBox from an internal IP. +INTERNAL_IPS = ('127.0.0.1', '::1') + +# Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: +# https://docs.djangoproject.com/en/stable/topics/logging/ +LOGGING = {} + +# Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users +# are permitted to access most data in NetBox (excluding secrets) but not make any changes. +LOGIN_REQUIRED = $LOGIN_REQUIRED + +# The length of time (in seconds) for which a user will remain logged into the web UI before being prompted to +# re-authenticate. (Default: 1209600 [14 days]) +LOGIN_TIMEOUT = None + +# Setting this to True will display a "maintenance mode" banner at the top of every page. +MAINTENANCE_MODE = False + +# An API consumer can request an arbitrary number of objects =by appending the "limit" parameter to the URL (e.g. +# "?limit=1000"). This setting defines the maximum limit. Setting it to 0 or None will allow an API consumer to request +# all objects by specifying "?limit=0". +MAX_PAGE_SIZE = 1000 + +EOF + +if [ "$MEDIA_ROOT" != "" ]; then + cat << EOF +# The file path where uploaded media such as image attachments are stored. A trailing slash is not needed. Note that +# the default value of this setting is derived from the installed location. +MEDIA_ROOT = '$MEDIA_ROOT' + +EOF +fi + +cat << EOF +# By default uploaded media is stored on the local filesystem. Using Django-storages is also supported. Provide the +# class path of the storage driver in STORAGE_BACKEND and any configuration options in STORAGE_CONFIG. For example: +# STORAGE_BACKEND = 'storages.backends.s3boto3.S3Boto3Storage' +# STORAGE_CONFIG = { +# 'AWS_ACCESS_KEY_ID': 'Key ID', +# 'AWS_SECRET_ACCESS_KEY': 'Secret', +# 'AWS_STORAGE_BUCKET_NAME': 'netbox', +# 'AWS_S3_REGION_NAME': 'eu-west-1', +# } + +# Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics' +METRICS_ENABLED = False + +# Credentials that NetBox will uses to authenticate to devices when connecting via NAPALM. +NAPALM_USERNAME = '' +NAPALM_PASSWORD = '' + +# NAPALM timeout (in seconds). (Default: 30) +NAPALM_TIMEOUT = 30 + +# NAPALM optional arguments (see http://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must +# be provided as a dictionary. +NAPALM_ARGS = {} + +# Determine how many objects to display per page within a list. (Default: 50) +PAGINATE_COUNT = 50 + +# Enable installed plugins. Add the name of each plugin to the list. +PLUGINS = [] + +# Plugins configuration settings. These settings are used by various plugins that the user may have installed. +# Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. +# PLUGINS_CONFIG = { +# 'my_plugin': { +# 'foo': 'bar', +# 'buzz': 'bazz' +# } +# } + +# When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to +# prefer IPv4 instead. +PREFER_IPV4 = False + +# Rack elevation size defaults, in pixels. For best results, the ratio of width to height should be roughly 10:1. +RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = 22 +RACK_ELEVATION_DEFAULT_UNIT_WIDTH = 220 + +EOF + +if [ "$USE_LDAP" ]; then + cat << EOF +# Remote authentication support with ldap +REMOTE_AUTH_ENABLED = True +REMOTE_AUTH_BACKEND = 'netbox.authentication.LDAPBackend' +EOF +else + cat << EOF +# Remote authentication support +REMOTE_AUTH_ENABLED = False +REMOTE_AUTH_BACKEND = 'netbox.authentication.RemoteUserBackend' +EOF +fi + +cat << EOF +REMOTE_AUTH_HEADER = 'HTTP_REMOTE_USER' +REMOTE_AUTH_AUTO_CREATE_USER = True +REMOTE_AUTH_DEFAULT_GROUPS = [] +REMOTE_AUTH_DEFAULT_PERMISSIONS = {} + +# This determines how often the GitHub API is called to check the latest release of NetBox. Must be at least 1 hour. +RELEASE_CHECK_TIMEOUT = 24 * 3600 + +# This repository is used to check whether there is a new release of NetBox available. Set to None to disable the +# version check or use the URL below to check for release in the official NetBox repository. + +EOF + +if [ "$UPDATE_CHECK" != "" ]; then + cat << EOF +RELEASE_CHECK_URL = 'https://api.github.com/repos/netbox-community/netbox/releases' + +EOF +else + cat << EOF +RELEASE_CHECK_URL = None + +EOF +fi + +if [ "$REPORTS_ROOT" != "" ]; then + cat << EOF +# The file path where custom reports will be stored. A trailing slash is not needed. Note that the default value of +# this setting is derived from the installed location. +REPORTS_ROOT = '$REPORTS_ROOT' + +EOF +fi + +if [ "$SCRIPTS_ROOT" != "" ]; then + cat << EOF +# The file path where custom scripts will be stored. A trailing slash is not needed. Note that the default value of +# this setting is derived from the installed location. +SCRIPTS_ROOT = '$SCRIPTS_ROOT' + +EOF +fi + +cat << EOF +# By default, NetBox will store session data in the database. Alternatively, a file path can be specified here to use +# local file storage instead. (This can be useful for enabling authentication on a standby instance with read-only +# database access.) Note that the user as which NetBox runs must have read and write permissions to this path. +SESSION_FILE_PATH = None + +# Time zone (default: UTC) +TIME_ZONE = 'UTC' + +# Date/time formatting. See the following link for supported formats: +# https://docs.djangoproject.com/en/stable/ref/templates/builtins/#date +DATE_FORMAT = 'N j, Y' +SHORT_DATE_FORMAT = 'Y-m-d' +TIME_FORMAT = 'g:i a' +SHORT_TIME_FORMAT = 'H:i:s' +DATETIME_FORMAT = 'N j, Y g:i a' +SHORT_DATETIME_FORMAT = 'Y-m-d H:i' +EOF diff --git a/type/__netbox/files/ldap_config.py.sh b/type/__netbox/files/ldap_config.py.sh new file mode 100755 index 0000000..4e6b099 --- /dev/null +++ b/type/__netbox/files/ldap_config.py.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +# no configuration if there are no ldap parameters +if [ -z "$USE_LDAP" ]; then + # skip + cat << EOF +############################## +# LDAP-backed authentication # +############################## + +# no options set +EOF + exit 0 +fi + + +cat << EOF +############################## +# LDAP-backed authentication # +############################## + +import ldap +from django_auth_ldap.config import LDAPSearch, PosixGroupType + +# Server URI +AUTH_LDAP_SERVER_URI = "$LDAP_SERVER" + +# Set the DN and password for the NetBox service account. +AUTH_LDAP_BIND_DN = "$LDAP_BIND_DN" +AUTH_LDAP_BIND_PASSWORD = "$LDAP_BIND_PASSWORD" + +# Search for user entry. +AUTH_LDAP_USER_SEARCH = LDAPSearch("$LDAP_USER_BASE", + ldap.SCOPE_SUBTREE, + "(uid=%(user)s)") + +# You can map user attributes to Django attributes as so. +AUTH_LDAP_USER_ATTR_MAP = { + "first_name": "givenName", + "last_name": "sn", + "email": "mail" +} +EOF + +if [ "$LDAP_GROUP_BASE" != "" ]; then + cat << EOF + +# This search ought to return all groups to which the user belongs. django_auth_ldap uses this to determine group +# hierarchy. +AUTH_LDAP_GROUP_SEARCH = LDAPSearch("$LDAP_GROUP_BASE", ldap.SCOPE_SUBTREE, + "(objectClass=posixGroup)") +AUTH_LDAP_GROUP_TYPE = PosixGroupType() + +# Mirror LDAP group assignments. +AUTH_LDAP_MIRROR_GROUPS = True +# For more granular permissions, map LDAP groups to Django groups. +AUTH_LDAP_FIND_GROUP_PERMS = True +EOF + + if [ "$LDAP_REQUIRE_GROUP" != "" ]; then + cat << EOF + +# Define a group required to login. +AUTH_LDAP_REQUIRE_GROUP = "$LDAP_REQUIRE_GROUP" +EOF + fi + + cat << EOF + +# Define special user types using groups. Exercise great caution when assigning superuser status. +AUTH_LDAP_USER_FLAGS_BY_GROUP = { +EOF + # superuser + if [ "$LDAP_SUPERUSER_GROUP" != "" ]; then + echo " \"is_superuser\": \"$LDAP_SUPERUSER_GROUP\"," + fi + # staff user + if [ "$LDAP_STAFF_GROUP" != "" ]; then + echo " \"is_staff\": \"$LDAP_STAFF_GROUP\"," + fi + echo "}" +fi diff --git a/type/__netbox/files/netbox-rq.service b/type/__netbox/files/netbox-rq.service new file mode 100644 index 0000000..330e675 --- /dev/null +++ b/type/__netbox/files/netbox-rq.service @@ -0,0 +1,24 @@ +[Unit] +Description=NetBox Request Queue Worker +Documentation=https://netbox.readthedocs.io/en/stable/ +PartOf=netbox.service +Wants=network.target +After=netbox.service +After=network.target +After=redis-server.service postgresql.service + +[Service] +Type=simple + +User=netbox +Group=netbox +WorkingDirectory=/opt/netbox + +ExecStart=/opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py rqworker + +Restart=on-failure +RestartSec=30 +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/type/__netbox/files/netbox.service b/type/__netbox/files/netbox.service new file mode 100644 index 0000000..68010e9 --- /dev/null +++ b/type/__netbox/files/netbox.service @@ -0,0 +1,13 @@ +[Unit] +Description=NetBox Service Wrapper +Documentation=https://netbox.readthedocs.io/en/stable/ +Wants=network.target +After=network.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/true + +[Install] +WantedBy=multi-user.target diff --git a/type/__netbox/files/netbox.socket.sh b/type/__netbox/files/netbox.socket.sh new file mode 100755 index 0000000..2ef9e81 --- /dev/null +++ b/type/__netbox/files/netbox.socket.sh @@ -0,0 +1,33 @@ +#!/bin/sh -e +# __netbox/files/netbox.socket.sh + +# This is shared between all WSGI-server types. + +# Arguments: +# 1: File which list all sockets to listen on (sepearated by \n) + +if [ $# -ne 1 ]; then + printf "netbox.socket.sh: argument \$1 missing or too much given!\n" >&2 + exit 1 +fi + + +cat << UNIT +[Unit] +Description=Socket for NetBox via $TYPE + +[Socket] +UNIT + +# read all sockets to listen to +while read -r line; do + printf "ListenStream=%s\n" "$line" +done < "$1" + +cat << UNIT +SocketUser=netbox +SocketGroup=www-data + +[Install] +WantedBy=sockets.target +UNIT diff --git a/type/__netbox/gencode-remote b/type/__netbox/gencode-remote new file mode 100755 index 0000000..5d4b7be --- /dev/null +++ b/type/__netbox/gencode-remote @@ -0,0 +1,120 @@ +#!/bin/sh -e + +old_version="$(cat "$__object/explorer/version")" +VERSION=$(cat "$__object/parameter/version") + +src="netbox-$VERSION" +archive="v$VERSION.tar.gz" +url="https://github.com/netbox-community/netbox/archive/$archive" +install_dir=/opt/netbox/netbox + +if [ "$VERSION" != "$old_version" ]; then + cat << EOF +# Ensure that coreutils is installed. +if [ ! -x \$(which mktemp) ]; then + echo "mktemp is not available on the remote host." >&2 + exit 1 +fi + +# Create temporary working directory. +tmpdir=\$(mktemp -d) +cd "\$tmpdir" + +# Download and extract sources. +curl -sS -L '$url' > '$archive' +tar xf '$archive' + + +# virtualenv is given already by __pyvenv, just using it + +# backup requirement files +if [ -f /opt/netbox/requirements.txt ]; then + mv /opt/netbox/requirements.txt /opt/netbox/old-requirements.txt +else + # preseve file-not-found errors and warnings + touch /opt/netbox/old-requirements.txt +fi +cp '$src/requirements.txt' /opt/netbox/ + +# Uninstall packages not required anymore +# if versions not be shortend, they will be ignored by pip, but not by comm +# all of this could be done with grep, too, but it's still must be shortend with awk +awk -F== '{print \$1}' '/opt/netbox/requirements.txt' | sort > "\$tmpdir/curr-reqs.txt" +awk -F== '{print \$1}' '/opt/netbox/old-requirements.txt' | sort > "\$tmpdir/old-reqs.txt" +comm -23 "\$tmpdir/old-reqs.txt" "\$tmpdir/curr-reqs.txt" > "\$tmpdir/pip-uninstall.txt" + +# only uninstall if something is available (to avoid errors cause of this) +if [ -s "\$tmpdir/pip-uninstall.txt" ]; then + /opt/netbox/venv/bin/pip3 uninstall -qy -r "\$tmpdir/pip-uninstall.txt" +fi + +# Install python dependencies. +# avoid gunicorn, because it will be done in an other type +grep -v "^gunicorn==" "\$tmpdir/$src/requirements.txt" \ + | xargs /opt/netbox/venv/bin/pip3 install -q +EOF + + if [ -f "$__object/parameter/ldap-server" ]; then + echo "/opt/netbox/venv/bin/pip3 install -q django-auth-ldap" + else + echo "/opt/netbox/venv/bin/pip3 uninstall -qy django-auth-ldap" + fi + + cat << EOF + +# Deploy sources and restore configuration. +rm -rf '$install_dir' +cp -r '$src/netbox' '$install_dir' +# force links to the cdist directory +ln -fs /opt/netbox/cdist/configuration.py '$install_dir/netbox/configuration.py' +ln -fs /opt/netbox/cdist/ldap_config.py '$install_dir/netbox/ldap_config.py' + +# Set final permissions. +chown -R netbox /opt/netbox + + +# NetBox manage scripts +# Run database migrations. +sudo -u netbox /opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py migrate +# Generate static assets. +sudo -u netbox /opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py collectstatic --no-input +# Delete any stale content types +sudo -u netbox /opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py remove_stale_contenttypes --no-input +# Delete any expired user sessions +sudo -u netbox /opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py clearsessions +# Clear all cached data +sudo -u netbox /opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py invalidate all + +# Remove temporary working directory. +cd / +rm -rf "\$tmpdir" + +# Save version after successful installation +printf "%s\\n" "$VERSION" > /opt/netbox/cdist/version + +EOF + + # meta + printf "installed %s\n" "$VERSION" >> "$__messages_out" + changes=yes +fi + +# check if configuration changed +if grep -q "^__file/opt/netbox/" "$__messages_in"; then + # meta + printf "configured\n" >> "$__messages_out" + changes=yes +fi + + +# Check for changes +if [ "$changes" = "yes" ]; then + # After the upstream upgrade.sh script, it's ok to migrate while the + # application is running ;) + + # restarting after changes + cat << EOF +# Restart service. All required services are included with netbox.service. +systemctl restart netbox +EOF +fi diff --git a/type/__netbox/man.rst b/type/__netbox/man.rst new file mode 100644 index 0000000..5f78f1d --- /dev/null +++ b/type/__netbox/man.rst @@ -0,0 +1,274 @@ +cdist-type__netbox(7) +===================== + +NAME +---- +cdist-type__netbox - Install and configure NetBox + + +DESCRIPTION +----------- +This (singleton) type installs and configures a NetBox instance, a web +application to help manage and document computer networks. + +It installs it with the user ``netbox`` at ``/opt/netbox`` with `python-venv`. +It setup systemd unit files for the services `netbox` and `netbox-rq`. The +`netbox` service only wrap all netbox related services, e.g. restarting and +so one will be delegated to all related services. + +The application is still not accessable because a WSGI server is required. To +access the application through WSGI, uWSGI or Gunicorn can be used. The setup +can be done via there own types `__netbox_gunicorn` and `__netbox_uwsgi`. + +The Gunicorn setup is recommended from the NetBox documentation. Consult each +manual page to decide. The types must be called after the `__netbox` type. + + +REQUIRED PARAMETERS +------------------- +version + NetBox version to be installed. You can find the correct and newest version + on GitHub at the NetBox project page under + "`Releases `_". + +database + PostgreSQL database name. + +database-user + PostgreSQL database user. + +database-password + PostgreSQL database password. + +host + Hostname (domain or IP address) on which the application is served. + Multiple hostnames are possible; given as multiple arguments. + + +OPTIONAL PARAMETERS +------------------- +secret-key + Random secret key of at least 50 alphanumeric characters and symbols. This + key must be unique to this installation and must not be shared outside the + local system. If no secret key is given, the type generates an own 50 chars + long key and saves it on the remote host to remember it for the next run. + + The secret, random string is used to assist in the creation new + cryptographic hashes for passwords and HTTP cookies. It is not directly + used for hasing user passwords or for encrpted storage. It can be changed + at any time, but will invalidate all existing sessions. + +database-host + PostgreSQL database hostname. Defaults to ``localhost``. + +database-port + PostgreSQL database port. Defaults to empty (uses the default port). + +ldap-server + LDAP server URI. Enables LDAP-backed authentication if specified. + +ldap-bind-dn + DN for the NetBox service account. Required for LDAP authentication. + +ldap-bind-password + Password for the NetBox service account. Required for LDAP authentication. + +ldap-user-base + Base used for searching user entries. Required for LDAP authentication. + +ldap-group-base + Base used for searching group entries. + +ldap-require-group + Group required to login. + +ldap-staff-group + Make members of this group to "staff". This gives the users "Admin Access", + which means access to the "NetBox Administration" site. + +ldap-superuser-group + Make members of this groups superusers. + +redis-host + Redis database hostname. Defaults to ``localhost``. + +redis-port + Redis database port. Defaults to ``6379``. + +redis-password + Redis password. Defaults to empty password. + +redis-dbid-offset + Offset to set the redis database id's. The `tasks` database id is + `offset + 0` and `caching` is `offset + 1`. The offset defaults to ``0``. + +smtp-host + Host of the SMTP email server. Defaults to ``localhost``. + +smtp-port + Port of the SMTP email server. Defaults to ``25``. + +smtp-user + Username to access the SMTP email server. Defaults to empty. + +smtp-password + Password to access the SMTP email server. Defaults to empty. + +smtp-from-email + Email from which NetBox will be sent of. Defaults to empty. + +basepath + Base URL path if accessing netbox within a directory instead of directly the + webroot ``/``. For example, if installed at https://example.com/netbox/, set + the value ``netbox/``. + +https-proxy + Proxy which will be used with any HTTP request like webhooks. + +data-root + This parameter set's the media, reports and scripts root to subdirectories + of the given directory. Values can be overwritten by special parameters like + `--media-root` for example. Use this option if you want to store persistant + data of netbox on an other partition. A trailing slash is not needed. + + The data directories have following predefined sub-directory names: + + media root: + ``$data_root/media`` + reports root: + ``$data_root/reports`` + scripts root: + ``$data_root/scripts`` + + To preserve all data from installation upgrades - which just replace the + installation directory - the data will be kept in the netbox home directory + rather than the installation directory by default (``/opt/netbox/data/``). + This way, no data will be deleted after the installation directory + replacement because it remains outside of the installation directory. + +media-root + The file path to where media files (like image attachments) are stored. + Change this path if you require to store data on an other partiotion. + A trailing slash is not needed. Defaults to ``$data_root/media``. + +reports-root + The file path of where custom reports are kept. Change this path if you + require to store data on an other partition. A trailing slash is not + needed. Defaults to ``$data_root/reports``. + +scripts-root + The file path of where custom scripts are kept. Change this path if you + require to store data on an other partition. A trailing slash is not + needed. Defaults to ``$data_root/scripts``. + + +BOOLEAN PARAMETERS +------------------ +redis-ssl + Enables a secure TLS/SSL connection to the redis database. By default, ssl + is disabled. + +smtp-use-tls + Uses TLS to connect to the SMTP email server. `See documentation + `__ + for more information. + +smtp-use-ssl + Uses implicit TLS with the SMTP email server. `See documentation + `__ + for more information. + +login-required + Sets if a login is required to access all sites. By default, anonymous + users can see most data (excluding secrets) but not make any changes. + +update-notify + Enables the NetBox version check for new upstream updates. It checks every + 24 hours for new releases and notify the admin users in the gui if any. + + +MESSAGES +-------- +installed $VERSION + Netbox was fresh installed or updated. The new version number is appended. + +configured + Some configuration files got updated and therefore the service was + restarted. This message will not be echoed if configuration got updated due + a standard installation. + + +EXAMPLES +-------- + +.. code-block:: sh + + __netbox --version 2.8.7 --database netbox \ + --database-password "secretsecretsecret" \ + --secret-key "secretsecretsecret" \ + --host "${__target_host:?}" \ + --host "cool-netbox.xyz" \ + --ldap-server "ldaps://ldap.domain.tld" \ + --ldap-bind-dn "uid=netbox,ou=services,dc=domain,dc=tld" \ + --ldap-bind-password "secretsecretsecret" \ + --ldap-user-base "ou=users,dc=domain,dc=tld" \ + --ldap-group-base "ou=groups,dc=domain,dc=tld" \ + --ldap-require-group "cn=netbox-login,ou=groups,dc=domain,dc=tld" \ + --ldap-superuser-group "cn=netbox-admin,ou=groups,dc=domain,dc=tld" + # using recommended gunicorn setup + require="__netbox" __netbox_gunicorn + + +NOTES +----- +The configuration of NetBox contains more optional settings than that what can +be set with this type. If you think an important setting is missing or there +is a more good way to inject python code for dynamic configuration variables, +you are welcome to contribute! + +- `Possible optional settings + `_ + +If you not setup ldap authentification, you may be interested into how to +`setting up a super user +`_ +directly on the machine to be able to access and use NetBox. + +You may also be interested of writing a own type which handles the creation of +the super user. To do this non-interactivly, see the ansible role as `reference +`_. + +If you change the secret key while the netbox instance is running, there is a +time frame where the access to the application corrupts the whole database. +Then, you need to restore a backup or wipe the database. + +Currently, the cause is not clear, but it should work if you do not touch +netbox while the configuration is done (do not shut it down, too). It only +applies for changes of the secret key, which not happen normally. + +Maybe the `--restart` flag for the `__systemd_unit` types is not the best idea, +but avoids that the changes will not be applied. It could be solved if the type +would send messages from his actions. + + +SEE ALSO +-------- +`NetBox documentation `_ + +:strong:`cdist-type__netbox_gunicorn`\ (7) +:strong:`cdist-type__netbox_uwsgi`\ (7) + + +AUTHORS +------- +Timothée Floure +Matthias Stecher + + +COPYING +------- +Copyright \(C) 2020 Timothée Floure. +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/type/__netbox/manifest b/type/__netbox/manifest new file mode 100755 index 0000000..4be49bd --- /dev/null +++ b/type/__netbox/manifest @@ -0,0 +1,226 @@ +#!/bin/sh -e + +os=$(cat "$__global/explorer/os") + +case "$os" in + debian|ubuntu) + # Install netbox dependencies. + for pkg in python3-pip python3-venv python3-dev build-essential libxml2-dev \ + libxslt1-dev libffi-dev libpq-dev libssl-dev zlib1g-dev curl sudo; do + __package $pkg + done + + if [ -f "$__object/parameter/ldap-server" ]; then + for pkg in libldap2-dev libsasl2-dev libssl-dev; do + __package $pkg + done + fi + ;; + *) + printf "Your operating system (%s) is currently not supported by this type (%s)\n" "$os" "${__type##*/}" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + + +DATABASE_NAME=$(cat "$__object/parameter/database") +export DATABASE_NAME +DATABASE_USER="$(cat "$__object/parameter/database-user")" +export DATABASE_USER +DATABASE_PASSWORD=$(cat "$__object/parameter/database-password") +export DATABASE_PASSWORD +DATABASE_HOST="$(cat "$__object/parameter/database-host")" +export DATABASE_HOST +DATABASE_PORT="$(cat "$__object/parameter/database-port")" +export DATABASE_PORT + +# list of hosts +ALLOWED_HOSTS="" +while read -r hostname; do + # shellcheck disable=SC2089 + ALLOWED_HOSTS="$ALLOWED_HOSTS '$hostname'," +done < "$__object/parameter/host" +# shellcheck disable=SC2090 +export ALLOWED_HOSTS + +if [ -f "$__object/parameter/secret-key" ]; then + SECRET_KEY=$(cat "$__object/parameter/secret-key") +elif [ -s "$__object/explorer/secretkey" ]; then + # take the key that is already used + SECRET_KEY="$(cat "$__object/explorer/secretkey")" +else + # Can be done over netbox/generate_secret_key.py too, but it can't be + # generated right now where it's required (only if it's preloaded for + # this type to execute it now). + # Generates a 50-character long key with the same character set like + # the helper script. Must escape the '-' to be no character range. + SECRET_KEY="$(tr -cd '!@#$%^&*(\-_=+)[:alnum:]' < /dev/urandom | head -c50)" +fi +export SECRET_KEY + +if [ -f "$__object/parameter/ldap-server" ]; then + LDAP_SERVER=$(cat "$__object/parameter/ldap-server") + USE_LDAP=yes + export LDAP_SERVER +fi +if [ -f "$__object/parameter/ldap-bind-dn" ]; then + LDAP_BIND_DN=$(cat "$__object/parameter/ldap-bind-dn") + USE_LDAP=yes + export LDAP_BIND_DN +fi +if [ -f "$__object/parameter/ldap-bind-password" ]; then + LDAP_BIND_PASSWORD=$(cat "$__object/parameter/ldap-bind-password") + USE_LDAP=yes + export LDAP_BIND_PASSWORD +fi +if [ -f "$__object/parameter/ldap-user-base" ]; then + LDAP_USER_BASE=$(cat "$__object/parameter/ldap-user-base") + USE_LDAP=yes + export LDAP_USER_BASE +fi +if [ -f "$__object/parameter/ldap-group-base" ]; then + LDAP_GROUP_BASE=$(cat "$__object/parameter/ldap-group-base") + export LDAP_GROUP_BASE +fi +if [ -f "$__object/parameter/ldap-require-group" ]; then + LDAP_REQUIRE_GROUP=$(cat "$__object/parameter/ldap-require-group") + export LDAP_REQUIRE_GROUP +fi +if [ -f "$__object/parameter/ldap-superuser-group" ]; then + LDAP_SUPERUSER_GROUP=$(cat "$__object/parameter/ldap-superuser-group") + export LDAP_SUPERUSER_GROUP +fi +if [ -f "$__object/parameter/ldap-staff-group" ]; then + LDAP_STAFF_GROUP="$(cat "$__object/parameter/ldap-staff-group")" + export LDAP_STAFF_GROUP +fi +# export if base ldap parameters are used +export USE_LDAP + +# have default values +REDIS_HOST="$(cat "$__object/parameter/redis-host")" +export REDIS_HOST +REDIS_PORT="$(cat "$__object/parameter/redis-port")" +export REDIS_PORT +REDIS_PASSWORD="$(cat "$__object/parameter/redis-password")" +export REDIS_PASSWORD +REDIS_DBID_OFFSET="$(cat "$__object/parameter/redis-dbid-offset")" +export REDIS_DBID_OFFSET +if [ -f "$__object/parameter/redis-ssl" ]; then + REDIS_SSL="True" +else + REDIS_SSL="False" +fi +export REDIS_SSL + +SMTP_HOST="$(cat "$__object/parameter/smtp-host")" +export SMTP_HOST +SMTP_PORT="$(cat "$__object/parameter/smtp-port")" +export SMTP_PORT +SMTP_USER="$(cat "$__object/parameter/smtp-user")" +export SMTP_USER +SMTP_PASSWORD="$(cat "$__object/parameter/smtp-password")" +export SMTP_PASSWORD +SMTP_FROM_EMAIL="$(cat "$__object/parameter/smtp-from-email")" +export SMTP_FROM_EMAIL + +if [ -f "$__object/parameter/smtp-use-ssl" ]; then + SMTP_USE_SSL="True" +else + SMTP_USE_SSL="False" +fi +export SMTP_USE_SSL +if [ -f "$__object/parameter/smtp-use-tls" ]; then + if [ "$SMTP_USE_SSL" = "True" ]; then + echo "options --smtp-use-ssl and --smtp-use-tls are not compatible" >&2 + exit 2 + fi + SMTP_USE_TLS="True" +else + SMTP_USE_TLS="False" +fi +export SMTP_USE_TLS + +BASEPATH="$(cat "$__object/parameter/basepath")" +export BASEPATH + +if [ -f "$__object/parameter/http-proxy" ]; then + HTTP_PROXY=$(cat "$__object/parameter/http-proxy") + export HTTP_PROXY +fi +if [ -f "$__object/parameter/https-proxy" ]; then + HTTPS_PROXY=$(cat "$__object/parameter/https-proxy") + export HTTPS_PROXY +fi + +if [ -f "$__object/parameter/login-required" ]; then + LOGIN_REQUIRED="True" +else + LOGIN_REQUIRED="False" +fi +export LOGIN_REQUIRED + +data_root="$(cat "$__object/parameter/data-root")" +MEDIA_ROOT="$data_root/media" +REPORTS_ROOT="$data_root/reports" +SCRIPTS_ROOT="$data_root/scripts" + +if [ -f "$__object/parameter/media-root" ]; then + MEDIA_ROOT="$(cat "$__object/parameter/media-root")" +fi +export MEDIA_ROOT +if [ -f "$__object/parameter/reports-root" ]; then + REPORTS_ROOT="$(cat "$__object/parameter/reports-root")" +fi +export REPORTS_ROOT +if [ -f "$__object/parameter/scripts-root" ]; then + SCRIPTS_ROOT="$(cat "$__object/parameter/scripts-root")" +fi +export SCRIPTS_ROOT + +if [ -f "$__object/parameter/update-notify" ]; then + UPDATE_CHECK="yes" + export UPDATE_CHECK +fi + + +# Create system user used to run netbox. +__user netbox --system --home /opt/netbox --create-home +# Generate python environment (user will be set by gencode-remote) +require="__user/netbox" __pyvenv /opt/netbox/venv/ + +# Generate and upload netbox configuration. +mkdir -p "$__object/files" +"$__type/files/configuration.py.sh" > "$__object/files/configuration.py" +"$__type/files/ldap_config.py.sh" > "$__object/files/ldap_config.py" + +require="__user/netbox" __directory /opt/netbox/cdist +require="__directory/opt/netbox/cdist" __file \ + /opt/netbox/cdist/configuration.py --mode 640 --owner netbox \ + --source "$__object/files/configuration.py" + +if [ -f "$__object/parameter/ldap-server" ]; then + require="__directory/opt/netbox/cdist" __file \ + /opt/netbox/cdist/ldap_config.py --mode 640 --owner netbox \ + --source "$__object/files/ldap_config.py" +else + require="__directory/opt/netbox/cdist" __file \ + /opt/netbox/cdist/ldap_config.py --state absent +fi + +# save secret +require="__directory/opt/netbox/cdist" __file /opt/netbox/cdist/secretkey \ + --mode 400 --owner netbox --source - << SECRET +$SECRET_KEY +SECRET + + +# Upload systemd unit for worker and wsgi service +# does not restart netbox on change cause it only restart all other services +__systemd_unit netbox.service \ + --source "$__type/files/netbox.service" \ + --enablement-state enabled +__systemd_unit netbox-rq.service \ + --source "$__type/files/netbox-rq.service" \ + --enablement-state enabled --restart diff --git a/type/__netbox/parameter/boolean b/type/__netbox/parameter/boolean new file mode 100644 index 0000000..d568037 --- /dev/null +++ b/type/__netbox/parameter/boolean @@ -0,0 +1,5 @@ +redis-ssl +smtp-use-ssl +smtp-use-tls +login-required +update-notify diff --git a/type/__netbox/parameter/default/basepath b/type/__netbox/parameter/default/basepath new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/basepath @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/default/data-root b/type/__netbox/parameter/default/data-root new file mode 100644 index 0000000..45faab0 --- /dev/null +++ b/type/__netbox/parameter/default/data-root @@ -0,0 +1 @@ +/opt/netbox/data diff --git a/type/__netbox/parameter/default/database-host b/type/__netbox/parameter/default/database-host new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/type/__netbox/parameter/default/database-host @@ -0,0 +1 @@ +localhost diff --git a/type/__netbox/parameter/default/database-port b/type/__netbox/parameter/default/database-port new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/database-port @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/default/redis-dbid-offset b/type/__netbox/parameter/default/redis-dbid-offset new file mode 100644 index 0000000..573541a --- /dev/null +++ b/type/__netbox/parameter/default/redis-dbid-offset @@ -0,0 +1 @@ +0 diff --git a/type/__netbox/parameter/default/redis-host b/type/__netbox/parameter/default/redis-host new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/type/__netbox/parameter/default/redis-host @@ -0,0 +1 @@ +localhost diff --git a/type/__netbox/parameter/default/redis-password b/type/__netbox/parameter/default/redis-password new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/redis-password @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/default/redis-port b/type/__netbox/parameter/default/redis-port new file mode 100644 index 0000000..a8c4b8e --- /dev/null +++ b/type/__netbox/parameter/default/redis-port @@ -0,0 +1 @@ +6379 diff --git a/type/__netbox/parameter/default/smtp-from-email b/type/__netbox/parameter/default/smtp-from-email new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/smtp-from-email @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/default/smtp-host b/type/__netbox/parameter/default/smtp-host new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/type/__netbox/parameter/default/smtp-host @@ -0,0 +1 @@ +localhost diff --git a/type/__netbox/parameter/default/smtp-password b/type/__netbox/parameter/default/smtp-password new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/smtp-password @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/default/smtp-port b/type/__netbox/parameter/default/smtp-port new file mode 100644 index 0000000..7273c0f --- /dev/null +++ b/type/__netbox/parameter/default/smtp-port @@ -0,0 +1 @@ +25 diff --git a/type/__netbox/parameter/default/smtp-user b/type/__netbox/parameter/default/smtp-user new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/smtp-user @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/optional b/type/__netbox/parameter/optional new file mode 100644 index 0000000..9495f7a --- /dev/null +++ b/type/__netbox/parameter/optional @@ -0,0 +1,27 @@ +secret-key +database-host +database-port +ldap-server +ldap-bind-dn +ldap-bind-password +ldap-user-base +ldap-group-base +ldap-require-group +ldap-staff-group +ldap-superuser-group +redis-host +redis-port +redis-password +redis-dbid-offset +smtp-host +smtp-port +smtp-user +smtp-password +smtp-from-email +basepath +http-proxy +https-proxy +data-root +media-root +reports-root +scripts-root diff --git a/type/__netbox/parameter/required b/type/__netbox/parameter/required new file mode 100644 index 0000000..02fca9f --- /dev/null +++ b/type/__netbox/parameter/required @@ -0,0 +1,4 @@ +version +database +database-user +database-password diff --git a/type/__netbox/parameter/required_multiple b/type/__netbox/parameter/required_multiple new file mode 100644 index 0000000..c70dc2d --- /dev/null +++ b/type/__netbox/parameter/required_multiple @@ -0,0 +1 @@ +host diff --git a/type/__netbox/singleton b/type/__netbox/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__netbox_gunicorn/explorer/installed b/type/__netbox_gunicorn/explorer/installed new file mode 100755 index 0000000..c6f5d87 --- /dev/null +++ b/type/__netbox_gunicorn/explorer/installed @@ -0,0 +1,4 @@ +#!/bin/sh -e + +# print version if available +/opt/netbox/venv/bin/pip3 show gunicorn | awk '/Version:/{print $2}' diff --git a/type/__netbox_gunicorn/explorer/should_installed b/type/__netbox_gunicorn/explorer/should_installed new file mode 100755 index 0000000..073be92 --- /dev/null +++ b/type/__netbox_gunicorn/explorer/should_installed @@ -0,0 +1,3 @@ +#!/bin/sh -e + +awk -v FS="==" '$1 ~ /gunicorn/{print $2}' /opt/netbox/requirements.txt diff --git a/type/__netbox_gunicorn/files/gunicorn.py.sh b/type/__netbox_gunicorn/files/gunicorn.py.sh new file mode 100755 index 0000000..c1e6ee5 --- /dev/null +++ b/type/__netbox_gunicorn/files/gunicorn.py.sh @@ -0,0 +1,31 @@ +#!/bin/sh -e + +# Generates gunicorn config +# see https://docs.gunicorn.org/en/stable/settings.html + +# fix missing $__explorer +# see https://code.ungleich.ch/ungleich-public/cdist/-/issues/834 +__explorer="$__global/explorer" + +# size workes by cpu +cores="$(cat "$__explorer/cpu_cores")" + + +cat << EOF +# The IP address (typically localhost) and port that the Netbox WSGI process should listen on +#bind = done via systemd socket 'gunicorn-netbox.socket' + +# Number of gunicorn workers to spawn. This should typically be 2n+1, where +# n is the number of CPU cores present. +workers = $(( 2*cores + 1 )) + +# Number of threads per worker process +threads = 3 + +# Timeout (in seconds) for a request to complete +timeout = 120 + +# The maximum number of requests a worker can handle before being respawned +max_requests = 5000 +max_requests_jitter = 500 +EOF diff --git a/type/__netbox_gunicorn/files/netbox.service b/type/__netbox_gunicorn/files/netbox.service new file mode 100644 index 0000000..28b6b45 --- /dev/null +++ b/type/__netbox_gunicorn/files/netbox.service @@ -0,0 +1,29 @@ +[Unit] +Description=NetBox Gunicorn WSGI Service +Documentation=https://netbox.readthedocs.io/en/stable/ +PartOf=netbox.service +Requires=netbox-rq.service +Requires=gunicorn-netbox.socket +Wants=network.target +After=netbox.service +After=network.target +After=redis-server.service postgresql.service + +[Service] +Type=notify + +User=netbox +Group=netbox +WorkingDirectory=/opt/netbox + +ExecStart=/opt/netbox/venv/bin/gunicorn --pythonpath /opt/netbox/netbox --config /opt/netbox/gunicorn.py netbox.wsgi +# signals: https://docs.gunicorn.org/en/stable/signals.html +ExecReload=kill -HUP $MAINPID +ExecStop=kill -TERM $MAINPID +KillSignal=SIGQUIT + +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=netbox.service diff --git a/type/__netbox_gunicorn/files/netbox.socket.sh b/type/__netbox_gunicorn/files/netbox.socket.sh new file mode 120000 index 0000000..28ce920 --- /dev/null +++ b/type/__netbox_gunicorn/files/netbox.socket.sh @@ -0,0 +1 @@ +../../__netbox/files/netbox.socket.sh \ No newline at end of file diff --git a/type/__netbox_gunicorn/gencode-remote b/type/__netbox_gunicorn/gencode-remote new file mode 100755 index 0000000..4fae788 --- /dev/null +++ b/type/__netbox_gunicorn/gencode-remote @@ -0,0 +1,50 @@ +#!/bin/sh -e + +# control state +state="$(cat "$__object/parameter/state")" + +case "$state" in + # install gunicorn + enabled|disabled) + curr_installed="$(cat "$__object/explorer/installed")" + should_installed="$(cat "$__object/explorer/should_installed")" + + # gunicorn version change + if [ "$curr_installed" != "$should_installed" ]; then + # (re)installing gunicorn + echo "/opt/netbox/venv/bin/pip3 install 'gunicorn==$should_installed'" + + if [ "$curr_installed" != "" ]; then + printf "updated %s to %s\n" "$curr_installed" "$should_installed" \ + >> "$__messages_out" + else + printf "installed\n" >> "$__messages_out" + fi + do_restart=yes + fi + + # configuration changes + if grep -q "^__file/opt/netbox/gunicorn.py:" "$__messages_in"; then + do_restart=yes + printf "configured\n" >> "$__messages_out" + fi + + + # restart gunicorn + if [ "$do_restart" ] && [ "$state" != "disabled" ]; then + cat << EOF +# Restart service +systemctl restart gunicorn-netbox +EOF + fi + ;; + + # uninstall + absent) + # check if installed + if [ -s "$__object/explorer/installed" ]; then + # service already disabled + echo "/opt/netbox/venv/bin/pip3 uninstall -y gunicorn" + printf "uninstalled\n" >> "$__messages_out" + fi +esac diff --git a/type/__netbox_gunicorn/man.rst b/type/__netbox_gunicorn/man.rst new file mode 100644 index 0000000..8860294 --- /dev/null +++ b/type/__netbox_gunicorn/man.rst @@ -0,0 +1,117 @@ +cdist-type__netbox_gunicorn(7) +============================== + +NAME +---- +cdist-type__netbox_gunicorn - Run NetBox with Gunicorn + + +DESCRIPTION +----------- +This (singleton) type installs Gunicorn into the NetBox `python-venv` to host +the NetBox WSGI application. It provides the application as HTTP over the given +sockets. Static content must be served independent of Gunicorn. The Gunicorn +daemon is available as the `gunicorn-netbox` systemd service, but also +available via the `netbox` wrapper service. + +It will use systemd socket activation to listen to the given sockets. This +should allow to bind to privileaged ports (all below 1024) and hot reloads. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +state + Represents the state of the Gunciron application. Defaults to ``enabled``. + + enabled + The Gunicorn service is enabled and running. + disabled + The Gunicorn service is installed, but disabled. + absent + The uWSGI service is not installed and all configuration removed. + + This type does not guarantee anything about the running state of the + service. To be sure about the service is stopped or not, use the type + :strong:`cdist-type__systemd_service`\ (7) after this execution. + +bind-to + The hosts the gunicorn socket should be bind to. Formats are `IP`, + `IP:PORT`, `PATH` or anything other that systemd socket units will + understand as stream. Parameter can be set multiple times. Defaults + to ``127.0.0.1:8001``. + + +BOOLEAN PARAMETERS +------------------ +None. + + +MESSAGES +-------- +installed + The software was installed. + +upgraded $old to $new + The version of the gunicorn software was updated from `$old` to `$new`. + +configured + Configuration for gunicorn changed. + +uninstalled + The Gunicorn application was removed. + +In all cases where the application is still present, it restarts the service to +use the up-to-date version. + + +EXAMPLES +-------- + +.. code-block:: sh + + # simple + __netbox $args + require="__netbox" __netbox_gunicorn + + # with arguments + __netbox $args + require="__netbox" __netbox_gunicorn \ + --bind-to 0.0.0.0:8001 \ + --bind-to 1.2.3.4:5678 + + # replace uwsgi with gunicorn + __netbox $args + require="__netbox" __netbox_uwsgi --state absent + # it should depend on __netbox_uwsgi if they use the same socket + require="__netbox_uwsgi" __netbox_gunicorn --state enabled + + # be sure the service is disabled + __netbox $args + require="__netbox" __netbox_gunicorn --state disabled + require="__netbox_gunicorn" __systemd_service gunicorn-netbox --state stopped + + +SEE ALSO +-------- +`Gunicorn Documentation `_ + +:strong:`cdist-type__netbox`\ (7) +:strong:`cdist-type__netbox_uwsgi`\ (7) + + +AUTHORS +------- +Matthias Stecher + + +COPYING +------- +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/type/__netbox_gunicorn/manifest b/type/__netbox_gunicorn/manifest new file mode 100755 index 0000000..5748e9d --- /dev/null +++ b/type/__netbox_gunicorn/manifest @@ -0,0 +1,57 @@ +#!/bin/sh -e +# __netbox_gunicorn/manifest + +# Check states +state="" +unit_state="" +param_state="$(cat "$__object/parameter/state")" + +case "$param_state" in + enabled|disabled) + state="present" + unit_state="$param_state" + ;; + + absent) + state="absent" + unit_state="disabled" + ;; + + *) + # does not exist + printf "The state '%s' does not exist, can't continue!\n" "$param_state" >&2 + exit 2 + ;; +esac + + +mkdir "$__object/files" + +if [ "$state" = "present" ]; then + # process template + "$__type/files/gunicorn.py.sh" > "$__object/files/gunicorn.py" + + # gunicorn config file + __file /opt/netbox/gunicorn.py \ + --mode 644 --owner netbox \ + --source "$__object/files/gunicorn.py" + +else + # absent config file + __file /opt/netbox/gunicorn.py --state absent +fi + + +TYPE="Gunicorn" +export TYPE + +"$__type/files/netbox.socket.sh" "$__object/parameter/bind-to" \ + > "$__object/files/netbox.socket" + +# install systemd files +__systemd_unit gunicorn-netbox.socket \ + --state "$state" --enablement-state "$unit_state" \ + --source "$__object/files/netbox.socket" --restart +__systemd_unit gunicorn-netbox.service \ + --state "$state" --enablement-state "$unit_state" \ + --source "$__type/files/netbox.service" --restart diff --git a/type/__netbox_gunicorn/parameter/default/bind-to b/type/__netbox_gunicorn/parameter/default/bind-to new file mode 100644 index 0000000..f4c980e --- /dev/null +++ b/type/__netbox_gunicorn/parameter/default/bind-to @@ -0,0 +1 @@ +127.0.0.1:8001 diff --git a/type/__netbox_gunicorn/parameter/default/state b/type/__netbox_gunicorn/parameter/default/state new file mode 100644 index 0000000..86981e6 --- /dev/null +++ b/type/__netbox_gunicorn/parameter/default/state @@ -0,0 +1 @@ +enabled diff --git a/type/__netbox_gunicorn/parameter/optional b/type/__netbox_gunicorn/parameter/optional new file mode 100644 index 0000000..ff72b5c --- /dev/null +++ b/type/__netbox_gunicorn/parameter/optional @@ -0,0 +1 @@ +state diff --git a/type/__netbox_gunicorn/parameter/optional_multiple b/type/__netbox_gunicorn/parameter/optional_multiple new file mode 100644 index 0000000..331c077 --- /dev/null +++ b/type/__netbox_gunicorn/parameter/optional_multiple @@ -0,0 +1 @@ +bind-to diff --git a/type/__netbox_gunicorn/singleton b/type/__netbox_gunicorn/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__netbox_uwsgi/explorer/bind-capability b/type/__netbox_uwsgi/explorer/bind-capability new file mode 100755 index 0000000..c5c0365 --- /dev/null +++ b/type/__netbox_uwsgi/explorer/bind-capability @@ -0,0 +1,12 @@ +#!/bin/sh -e +# explorer/bind-capablility + +# Checks if the uWSGI binary have the capability to bind to privileaged ports +# as a non-root user. It's required if no systemd sockets are used (cause of +# the use of multiple protocols etc.) + +binary="/opt/netbox/venv/bin/uwsgi" +# -v verifies if capability is set +if setcap -q -v CAP_NET_BIND_SERVICE+ep "$binary"; then + echo set +fi diff --git a/type/__netbox_uwsgi/explorer/installed b/type/__netbox_uwsgi/explorer/installed new file mode 100755 index 0000000..a2393d0 --- /dev/null +++ b/type/__netbox_uwsgi/explorer/installed @@ -0,0 +1,4 @@ +#!/bin/sh -e + +# print version if available +/opt/netbox/venv/bin/pip3 show uwsgi | awk '/Version:/{print $2}' diff --git a/type/__netbox_uwsgi/explorer/upgradeable b/type/__netbox_uwsgi/explorer/upgradeable new file mode 100755 index 0000000..f4b0a22 --- /dev/null +++ b/type/__netbox_uwsgi/explorer/upgradeable @@ -0,0 +1,4 @@ +#!/bin/sh -e + +# print latest version if availble +/opt/netbox/venv/bin/pip3 list --outdated | awk '$1 == "uwsgi" {print $3}' diff --git a/type/__netbox_uwsgi/files/netbox.service.sh b/type/__netbox_uwsgi/files/netbox.service.sh new file mode 100755 index 0000000..3705769 --- /dev/null +++ b/type/__netbox_uwsgi/files/netbox.service.sh @@ -0,0 +1,40 @@ +#!/bin/sh -e + +cat << EOF +[Unit] +Description=Netbox uWSGI WSGI Service +Documentation=https://netbox.readthedocs.io/en/stable/ +PartOf=netbox.service +Requires=netbox-rq.service +EOF + +# Add dependency to own socket +if [ "$(cat "$__object/files/systemd_socket")" = "yes" ]; then + echo "Requires=uwsgi-netbox.socket" +fi + +cat << EOF +Wants=network.target +After=netbox.service +After=network.target +After=redis-server.service postgresql.service + +[Service] +Type=notify + +User=netbox +Group=netbox +WorkingDirectory=/opt/netbox + +ExecStart=/opt/netbox/venv/bin/uwsgi --master --chdir /opt/netbox/netbox --module netbox.wsgi uwsgi.ini +# signals: https://uwsgi-docs.readthedocs.io/en/latest/Management.html#signals-for-controlling-uwsgi +ExecReload=kill -HUP \$MAINPID +ExecStop=kill -INT \$MAINPID +KillSignal=SIGQUIT + +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=netbox.service +EOF diff --git a/type/__netbox_uwsgi/files/netbox.socket.sh b/type/__netbox_uwsgi/files/netbox.socket.sh new file mode 120000 index 0000000..28ce920 --- /dev/null +++ b/type/__netbox_uwsgi/files/netbox.socket.sh @@ -0,0 +1 @@ +../../__netbox/files/netbox.socket.sh \ No newline at end of file diff --git a/type/__netbox_uwsgi/files/uwsgi.ini.sh b/type/__netbox_uwsgi/files/uwsgi.ini.sh new file mode 100755 index 0000000..4bae613 --- /dev/null +++ b/type/__netbox_uwsgi/files/uwsgi.ini.sh @@ -0,0 +1,60 @@ +#!/bin/sh -e + +# Generates uwsgi config +# see https://uwsgi-docs.readthedocs.io/en/latest/Options.html +# or https://uwsgi-docs-additions.readthedocs.io/en/latest/Options.html + +# params: +# 1: parameter name +# 2: parameter value file +# +# output: the lines for the configuration option +multi_options() { + while read -r line; do + printf "%s = %s\n" "$1" "$line" + done < "$2" +} + +# fix missing $__explorer +# see https://code.ungleich.ch/ungleich-public/cdist/-/issues/834 +__explorer="$__global/explorer" + +# size workes by cpu +cores="$(cat "$__explorer/cpu_cores")" + + +cat << EOF +[uwsgi] +; socket(s) to bind +EOF + +if [ "$SYSTEMD_SOCKET" != "yes" ]; then + # special protocol to bind + find "$__object/parameter/" -maxdepth 1 -name "*-bind" -print \ + | while read -r param; do + multi_options "$(basename "$param" | awk -F'-' '{print $1}')-socket" "$param" + done +else + # else, systemd will offer socket + echo "; sockets managed via 'uwsgi-netbox.socket'" + printf "protocol = %s\n" "$PROTOCOL" +fi + + +# multi-process settings +cat << EOF + +; processes and threads +processes = $(( 2*cores + 1 )) +threads = 2 +EOF + + +# optional mapping of static content +if [ "$STATIC_MAP" != "" ]; then + cat << EOF + +; map static content +static-map = /static=/opt/netbox/netbox/static +EOF +fi diff --git a/type/__netbox_uwsgi/gencode-remote b/type/__netbox_uwsgi/gencode-remote new file mode 100755 index 0000000..7c3b826 --- /dev/null +++ b/type/__netbox_uwsgi/gencode-remote @@ -0,0 +1,101 @@ +#!/bin/sh -e + +# control state +state="$(cat "$__object/parameter/state")" + +# Set capabilities to aquire privileaged ports as netbox user. Two modes are +# available to efficiently set capabilites. Assumes libcap-bin is installed as +# default on debian systems. +# +# Arguments: +# 1: mode to detect if capabilites are required to set ('set' or 'correct') +set_bind_cap() { + cap_mode="" # reset variable from the execution before + + # check if capabilites are required after given mode + case "$1" in + # assumes capabilites are not set (cause of new binaries) + set) + if [ "$SYSTEMD_SOCKET" != "yes" ]; then + cap_mode="+ep" + fi + ;; + + # check if capabilities have changed + correct) + if [ -s "$__object/explorer/bind-capability" ]; then + # capabilites are set + if [ "$SYSTEMD_SOCKET" = "yes" ]; then + cap_mode="-ep" # unset + fi + else + # capabilities are unset + if [ "$SYSTEMD_SOCKET" != "yes" ]; then + cap_mode="+ep" # set + fi + fi + ;; + + # faulty mode + *) + echo "called set_bind_cap incorrect (\$1 missing)" >&2 + ;; + esac + + # set capabilities if any + if [ "$cap_mode" ]; then + printf "setcap -q CAP_NET_BIND_SERVICE%s /opt/netbox/venv/bin/uwsgi\n" "$cap_mode" + fi +} +SYSTEMD_SOCKET="$(cat "$__object/files/systemd_socket")" + + +case "$state" in + # install uwsgi + enabled|disabled) + # not installed + if ! [ -s "$__object/explorer/installed" ]; then + echo "/opt/netbox/venv/bin/pip3 install -q uwsgi" + set_bind_cap set + do_restart=yes + printf "installed\n" >> "$__messages_out" + + # updates available + elif [ -s "$__object/explorer/upgradeable" ]; then + echo "/opt/netbox/venv/bin/pip3 install -q --upgrade uwsgi" + set_bind_cap set + do_restart=yes + printf "upgraded\n" >> "$__messages_out" + fi + + # changed configuration + if grep -q "^__file/opt/netbox/uwsgi.ini:" "$__messages_in"; then + do_restart=yes + printf "configured\n" >> "$__messages_out" + fi + + # if no capabilities were set yet, check if any are required + if [ -z "$cap_mode" ]; then + set_bind_cap correct + fi + + + # restart uwsgi + if [ "$do_restart" ] && [ "$state" != "disabled" ]; then + cat << EOF +# Restart service +systemctl restart uwsgi-netbox +EOF + fi + ;; + + # uninstall + absent) + # check if installed + if [ -s "$__object/explorer/installed" ]; then + # service already disabled + echo "/opt/netbox/venv/bin/pip3 uninstall -qy uwsgi" + printf "uninstalled\n" >> "$__messages_out" + fi + ;; +esac diff --git a/type/__netbox_uwsgi/man.rst b/type/__netbox_uwsgi/man.rst new file mode 100644 index 0000000..13dc6dc --- /dev/null +++ b/type/__netbox_uwsgi/man.rst @@ -0,0 +1,183 @@ +cdist-type__netbox_uwsgi(7) +=========================== + +NAME +---- +cdist-type__netbox_uwsgi - Run NetBox with uWSGI + + +DESCRIPTION +----------- +This (singleton) type installs uWSGI into the NetBox `python-venv`. It hosts +the NetBox WSGI application via the WSGI protocol. A further server must be +installed to provide it as HTTP and serve static content. It supports multiple +protocols like uwsgi, fastcgi or HTTP to comunicate with the proxy server. This +application is available via the `uwsgi-netbox` systemd service. It is +controllable via the `netbox` wrapper service, too. + +**As uWSGI will be started as netbox user, it does not have privileges to +bind to a privileaged port (all ports below 1024).** Because uWSGI will +drop privileages anyway before binding to a port, solutions are to use +the systemd sockets to activate the ports as root or set linux kernel +capabilites to bind to such a privileaged port. + +As systemd sockets (or uwsgi itself) do not allow to distinguish multiple +sockets if different protocols are used for different sockets, this type does +not use systemd sockets if it is requested from the user. Using the +``--bind-to`` and ``--protocol`` parameters, it uses the systemd socket +activation. Else, it set the different sockets and protocols natively to uwsgi +and add kernel capabilities to be able to listen to privileaged ports. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +state + Represents the state of the uWSGI application. Defaults to ``enabled``. + + enabled + The uWSGI service is enabled and running. + disabled + The uWSGI service is installed, but disabled. + absent + The uWSGI service is not installed and all configuration removed. + + This type does not guarantee anything about the running state of the + service. To be sure about the service is stopped or not, use the type + :strong:`cdist-type__systemd_service`\ (7) after this execution. + + +bind-to + The socket uwsgi should bind to. Must be UNIX/TCP (or anything that + systemd sockets accept as stream). Defaults to ``127.0.0.1:3031``. Can be + set multiple times. The used protocol is defined by ``--protocol``. + + **By setting up the socket via this parameter, it uses systemd sockets to + handle these.** This parameter will be ignored if a more detailed paramter + is given (``--$proto-bind``). + +protocol + The protocol which should be used for the socket given by the ``--bind-to`` + parameter. Possible values are ``uwsgi``, ``http``, ``fastcgi`` and + ``scgi``. If nothing given, it defaults to ``uwsgi``. + +scgi-bind, uwsgi-bind, http-bind, fastcgi-bind + Bind the application to a specific protocol instead of implicit uwsgi via + ``--bind-to``. If such parameter given, ``--bind-to`` will be ignored. Must + be a UNIX/TCP socket. Can be set multiple times. + + **By using such parameters instead of ``--bind-to``, no systemd sockets + will be used because it can not handle sockets for multiple protocols.** + Instead, the native socket binding will be used. It will add kernel + capabilites to bind to privileaged ports, too. This allow binds to ports + like 80 as netbox user. + + +BOOLEAN PARAMETERS +------------------ +serve-static + Setup uWSGI to serve the static content, too. This is generally not + recommended for real production setups, as it is the job of the reverse + proxy server, who will thread it as static cachable content. This option + is only recommended for small setups or direct usage of the uWSGI socket + like using it as standalone HTTP server for NetBox. + + **Hint**: This parameter does not work in junction with the `__netbox` + parameter ``--basepath``. It is because this type does not know the + parameter value and this case is very unlikly to happen; although an + implementation is not difficult. + + +MESSAGES +-------- +installed + The uwsgi service was installed. + +upgraded + The uwsgi service was upgraded. + +configured + The uwsgi configuration got updated. + +uninstalled + The uWSGI application was removed. + +In all cases where the application is still present, it restarts the service to +use the up-to-date version. + + +EXAMPLES +-------- + +.. code-block:: sh + + # simple + __netbox $args + require="__netbox" __netbox_uwsgi + + # with multiple binds + __netbox $args + require="__netbox" __netbox_uwsgi --bind-to 0.0.0.0:3032 \ + --bind-to 0.0.0.0:3033 + + # with multiple protocols + # parameter `--bind-to` will be ignored + # avoids systemd sockets, but can handle multiple protocols + __netbox $args + require="__netbox" __netbox_uwsgi --uwsgi-bind 0.0.0.0:3031 \ + --http-bind 0.0.0.0:8080 \ + --fastcgi-bind 1.2.3.4:5678 + + # as standalone server + __netbox $args + require="__netbox" __netbox_uwsgi --serve-static --http-bind 0.0.0.0:80 + + # replace gunicorn with uwsgi + __netbox $args + require="__netbox" __netbox_gunicorn --state absent + # it should depend on __netbox_gunicorn if they use the same socket + require="__netbox_gunicorn" __netbox_uwsgi --state enabled + + # be sure the service is disabled + __netbox $args + require="__netbox" __netbox_uwsgi --state disabled + require="__netbox_uwsgi" __systemd_service uwsgi-netbox --state stopped + + +NOTES +----- +If systemd sockets are used, uwsgi can not be reloaded because it does not +handle the socket correctly. It works by completly restarting uwsgi (because +it is near the same cause of the systemd socket) or tweaking the service unit +with the line ``StandardInput=socket``, which limits you to only one address +to bind to (else, the service will not start). + +Maybe someone is interested in enabling log files, because the "log to stdout" +is not the fanciest approach (because it is shown in the journal). See the +`uwsgi documentation ` for +reference. + + +SEE ALSO +-------- +`uWSGI Documentation `_ + +:strong:`cdist-type__netbox`\ (7) +:strong:`cdist-type__netbox_gunicorn`\ (7) + + +AUTHORS +------- +Matthias Stecher + + +COPYING +------- +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/type/__netbox_uwsgi/manifest b/type/__netbox_uwsgi/manifest new file mode 100755 index 0000000..7c593e8 --- /dev/null +++ b/type/__netbox_uwsgi/manifest @@ -0,0 +1,86 @@ +#!/bin/sh -e +# __netbox_uwsgi/manifest + +# Check states +state="" +unit_state="" +param_state="$(cat "$__object/parameter/state")" + +case "$param_state" in + enabled|disabled) + state="present" + unit_state="$param_state" + ;; + + absent) + state="absent" + unit_state="disabled" + ;; + + *) + # does not exist + printf "The state '%s' does not exist, can't continue!\n" "$param_state" >&2 + exit 2 + ;; +esac + + +mkdir "$__object/files" + +# check if systemd sockets will be used +if [ -f "$__object/parameter/bind-to" ]; then + SYSTEMD_SOCKET="yes" +fi +if find "$__object/parameter/" -maxdepth 1 -name "*-bind" -print -quit | grep -q .; then + SYSTEMD_SOCKET="no" +fi +echo "$SYSTEMD_SOCKET" > "$__object/files/systemd_socket" + +if [ "$state" = "present" ]; then + # already checked outside this if-clause + export SYSTEMD_SOCKET + + PROTOCOL="$(cat "$__object/parameter/protocol")" + export PROTOCOL + + if [ -f "$__object/parameter/serve-static" ]; then + STATIC_MAP="yes" + export STATIC_MAP + fi + + # process template + "$__type/files/uwsgi.ini.sh" > "$__object/files/uwsgi.ini" + + # uwsgi config file + # TODO maybe patching with __key_value cause of .ini ? + __file /opt/netbox/uwsgi.ini \ + --mode 644 --owner netbox \ + --source "$__object/files/uwsgi.ini" + +else + # absent config file + __file /opt/netbox/uwsgi.ini --state absent +fi + + +# handle the systemd socket +if [ "$SYSTEMD_SOCKET" = "yes" ]; then + TYPE="uWSGI" + export TYPE + + # generate and set the socket unit + "$__type/files/netbox.socket.sh" "$__object/parameter/bind-to" \ + > "$__object/files/netbox.socket" + __systemd_unit uwsgi-netbox.socket \ + --state "$state" --enablement-state "$unit_state" \ + --source "$__object/files/netbox.socket" --restart +else + # remove the systemd socket unit + __systemd_unit uwsgi-netbox.socket --state absent +fi + +# install service file +"$__type/files/netbox.service.sh" > "$__object/files/netbox.service" +__systemd_unit uwsgi-netbox.service \ + --state "$state" --enablement-state "$unit_state" \ + --source "$__object/files/netbox.service" --restart diff --git a/type/__netbox_uwsgi/parameter/boolean b/type/__netbox_uwsgi/parameter/boolean new file mode 100644 index 0000000..aa08196 --- /dev/null +++ b/type/__netbox_uwsgi/parameter/boolean @@ -0,0 +1 @@ +serve-static diff --git a/type/__netbox_uwsgi/parameter/default/bind-to b/type/__netbox_uwsgi/parameter/default/bind-to new file mode 100644 index 0000000..c696456 --- /dev/null +++ b/type/__netbox_uwsgi/parameter/default/bind-to @@ -0,0 +1 @@ +127.0.0.1:3031 diff --git a/type/__netbox_uwsgi/parameter/default/protocol b/type/__netbox_uwsgi/parameter/default/protocol new file mode 100644 index 0000000..caf986e --- /dev/null +++ b/type/__netbox_uwsgi/parameter/default/protocol @@ -0,0 +1 @@ +uwsgi diff --git a/type/__netbox_uwsgi/parameter/default/state b/type/__netbox_uwsgi/parameter/default/state new file mode 100644 index 0000000..86981e6 --- /dev/null +++ b/type/__netbox_uwsgi/parameter/default/state @@ -0,0 +1 @@ +enabled diff --git a/type/__netbox_uwsgi/parameter/optional b/type/__netbox_uwsgi/parameter/optional new file mode 100644 index 0000000..3284ccc --- /dev/null +++ b/type/__netbox_uwsgi/parameter/optional @@ -0,0 +1,2 @@ +state +protocol diff --git a/type/__netbox_uwsgi/parameter/optional_multiple b/type/__netbox_uwsgi/parameter/optional_multiple new file mode 100644 index 0000000..3f3e7d4 --- /dev/null +++ b/type/__netbox_uwsgi/parameter/optional_multiple @@ -0,0 +1,5 @@ +bind-to +uwsgi-bind +http-bind +fastcgi-bind +scgi-bind diff --git a/type/__netbox_uwsgi/singleton b/type/__netbox_uwsgi/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__root_mail_dma/files/aliases b/type/__root_mail_dma/files/aliases deleted file mode 100644 index d341318..0000000 --- a/type/__root_mail_dma/files/aliases +++ /dev/null @@ -1,68 +0,0 @@ -# Based off FreeBSD's /etc/aliases -# -# >>>>>>>>>> The program "newaliases" must be run after -# >> NOTE >> this file is updated for any changes to -# >>>>>>>>>> show through to sendmail. -# -# -# See also RFC 2142, `MAILBOX NAMES FOR COMMON SERVICES, ROLES -# AND FUNCTIONS', May 1997 -# http://tools.ietf.org/html/rfc2142 - -# Pretty much everything else in this file points to "root", so -# you would do well in either reading root's mailbox or forwarding -# root's email from here. - -# root: me@my.domain - - -# Basic system aliases -- these MUST be present -MAILER-DAEMON: postmaster -postmaster: root - -# General redirections for pseudo accounts -_dhcp: root -_pflogd: root -auditdistd: root -bin: root -bind: root -daemon: root -games: root -hast: root -kmem: root -mailnull: postmaster -man: root -news: root -nobody: root -operator: root -pop: root -proxy: root -smmsp: postmaster -sshd: root -system: root -toor: root -tty: root -usenet: news -uucp: root - -# Well-known aliases -- these should be filled in! -manager: root -dumper: root - -# BUSINESS-RELATED MAILBOX NAMES -info: root -marketing: root -sales: root -support: root - -# NETWORK OPERATIONS MAILBOX NAMES -abuse: root -noc: root -security: root - -# SUPPORT MAILBOX NAMES FOR SPECIFIC INTERNET SERVICES -ftp: root -ftp-bugs: ftp -hostmaster: root -webmaster: root -www: webmaster diff --git a/type/__root_mail_dma/gencode-remote b/type/__root_mail_dma/gencode-remote deleted file mode 100755 index 2961c09..0000000 --- a/type/__root_mail_dma/gencode-remote +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -e - -if [ -f "${__object}/parameter/send-test-email" ]; then - SEND_EMAIL="YES" -fi - -if [ "${SEND_EMAIL}" != "YES" ]; then - exit 0 -fi - -cat <`_ -- `DragonFly Handbook MTA `_ - - -AUTHORS -------- -Evilham - - -COPYING -------- -Copyright \(C) 2020 Evilham. 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/type/__root_mail_dma/manifest b/type/__root_mail_dma/manifest deleted file mode 100755 index abcaa5b..0000000 --- a/type/__root_mail_dma/manifest +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/sh -e - -os="$(cat "${__global}/explorer/os")" - -root_email="$(tr '\n' ',' < "${__object}/parameter/root-email" | sed -E 's/,+$//')" -smart_host="$(cat "${__object}/parameter/smart-host")" - -if [ -f "${__object}/parameter/mailname" ]; then - mailname="$(cat "${__object}/parameter/mailname")" -else - # default mailname behaviour is different in certain systems - case ${os} in - debian|devuan|ubuntu) - # Debian-like default to /etc/mailname - mailname="/etc/mailname" - ;; - *) - # Otherwise let's use the hostname - mailname="${__target_host}" - ;; - esac -fi - -aliases_file=/etc/mail/aliases -case ${os} in - debian|devuan|ubuntu) - # Debian-like requires installing DMA - __package dma - # Moving forward without DMA doesn't make much sense - export require="__package/dma" - aliases_file=/etc/aliases - ;; - freebsd) - # Disable sendmail + stop if necessary - __key_value \ - --file "/etc/rc.conf" \ - --comment "# Disable sendmail " \ - --key "sendmail_enable" \ - --delimiter "=" \ - --value "NONE" \ - --onchange "service sendmail onestop || true" \ - "sendmail_enable" - # Setup mailwrapper accordingly - __file /etc/mail/mailer.conf \ - --mode 0644 \ - --source '-' < /dev/stderr < + +COPYING +------- +Copyright \(C) 2020 Evilham. 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/type/__runit/manifest b/type/__runit/manifest new file mode 100755 index 0000000..195a70e --- /dev/null +++ b/type/__runit/manifest @@ -0,0 +1,10 @@ +#!/bin/sh -e + +__package "runit" + +__key_value \ + --file "/etc/rc.conf" \ + --key "runsvdir_enable" \ + --delimiter "=" \ + --value "yes" \ + "runsvdir_enable" diff --git a/type/__runit/singleton b/type/__runit/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__runit_service/man.rst b/type/__runit_service/man.rst new file mode 100644 index 0000000..7b1db84 --- /dev/null +++ b/type/__runit_service/man.rst @@ -0,0 +1,58 @@ +cdist-type__runit_service(7) +==================================== + +NAME +---- +cdist-type__runit_service - Create a runit-compatible service dir. + + +DESCRIPTION +----------- +Create a directory structure compatible with runit-like service management. + +Note that sv(8) and runsvdir(8) must be present on the target system, this can +be achieved with e.g. `__runit`. + +The `__object_id` will be used as the service name. + + +REQUIRED PARAMETERS +------------------- +source + File to save as /run. If set to '-', standard input will be used. + + +BOOLEAN PARAMETERS +------------------ +log + Setup logging with `svlogd -tt ./main`. + + +EXAMPLES +-------- + +.. code-block:: sh + + require="__runit" __runit_service tasksched \ + --source - << EOF + #!/bin/sh -e + cd "${HOME}/.local/share/tasksched" + exec ./server.js 2>&1 + EOF + + +SEE ALSO +-------- +:strong:`cdist-type__runit`\ (7) + + +AUTHORS +------- +Evilham + +COPYING +------- +Copyright \(C) 2020 Evilham. 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/type/__runit_service/manifest b/type/__runit_service/manifest new file mode 100755 index 0000000..29f3312 --- /dev/null +++ b/type/__runit_service/manifest @@ -0,0 +1,33 @@ +#!/bin/sh -e + +svdir="/var/service" +sv="${__object_id}" +state="present" +run_file="${svdir}/${sv}/run" + +source="$(cat "$__object/parameter/source")" +if [ "$source" = "-" ]; then + source="$__object/stdin" +fi + +# Create this service's directory +__directory --state "${state}" "${svdir}/${sv}" + +export require="__directory${svdir}/${sv}" + + +if [ -f "${__object}/parameter/log" ]; then + # Setup logger if requested + __directory --parents "${svdir}/${sv}/log/main" + export require="${require} __directory${svdir}/${sv}/log/main" + __file "${svdir}/${sv}/log/run" \ + --state "${state}" \ + --mode 0755 \ + --source "-" < + # local-data: "" + # o deny serves local data (if any), else, drops queries. + # o refuse serves local data (if any), else, replies with error. + # o static serves local data, else, nxdomain or nodata answer. + # o transparent gives local data, but resolves normally for other names + # o redirect serves the zone data for any subdomain in the zone. + # o nodefault can be used to normally resolve AS112 zones. + # o typetransparent resolves normally for other types and other names + # o inform acts like transparent, but logs client IP address + # o inform_deny drops queries and logs client IP address + # o inform_redirect redirects queries and logs client IP address + # o always_transparent, always_refuse, always_nxdomain, resolve in + # that way but ignore local data for that name + # o noview breaks out of that view towards global local-zones. + # + # defaults are localhost address, reverse for 127.0.0.1 and ::1 + # and nxdomain for AS112 zones. If you configure one of these zones + # the default content is omitted, or you can omit it with 'nodefault'. + # + # If you configure local-data without specifying local-zone, by + # default a transparent local-zone is created for the data. + # + # You can add locally served data with + # local-zone: "local." static + # local-data: "mycomputer.local. IN A 192.0.2.51" + # local-data: 'mytext.local TXT "content of text record"' + # + # You can override certain queries with + # local-data: "adserver.example.com A 127.0.0.1" + # + # You can redirect a domain to a fixed address with + # (this makes example.com, www.example.com, etc, all go to 192.0.2.3) + # local-zone: "example.com" redirect + # local-data: "example.com A 192.0.2.3" +$(generate_local_data) + # + # Shorthand to make PTR records, "IPv4 name" or "IPv6 name". + # You can also add PTR records using local-data directly, but then + # you need to do the reverse notation yourself. + # local-data-ptr: "192.0.2.3 www.example.com" + + # tag a localzone with a list of tag names (in "" with spaces between) + # local-zone-tag: "example.com" "tag2 tag3" + + # add a netblock specific override to a localzone, with zone type + # local-zone-override: "example.com" 192.0.2.0/24 refuse + + # service clients over TLS (on the TCP sockets), with plain DNS inside + # the TLS stream. Give the certificate to use and private key. + # default is "" (disabled). requires restart to take effect. + # tls-service-key: "path/to/privatekeyfile.key" + # tls-service-pem: "path/to/publiccertfile.pem" + # tls-port: 853 + + # cipher setting for TLSv1.2 + # tls-ciphers: "DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256" + # cipher setting for TLSv1.3 + # tls-ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" + + # Add the secret file for TLS Session Ticket. + # Secret file must be 80 bytes of random data. + # First key use to encrypt and decrypt TLS session tickets. + # Other keys use to decrypt only. + # requires restart to take effect. + # tls-session-ticket-keys: "path/to/secret_file1" + # tls-session-ticket-keys: "path/to/secret_file2" + + # request upstream over TLS (with plain DNS inside the TLS stream). + # Default is no. Can be turned on and off with unbound-control. + # tls-upstream: no + + # Certificates used to authenticate connections made upstream. + # tls-cert-bundle: "" + + # Add system certs to the cert bundle, from the Windows Cert Store + # tls-win-cert: no + + # Also serve tls on these port numbers (eg. 443, ...), by listing + # tls-additional-port: portno for each of the port numbers. + + # DNS64 prefix. Must be specified when DNS64 is use. + # Enable dns64 in module-config. Used to synthesize IPv6 from IPv4. + # dns64-prefix: $DNS64_PREFIX" + $(generate_dns64_prefix) + + # DNS64 ignore AAAA records for these domains and use A instead. + # dns64-ignore-aaaa: "example.com" + + # ratelimit for uncached, new queries, this limits recursion effort. + # ratelimiting is experimental, and may help against randomqueryflood. + # if 0(default) it is disabled, otherwise state qps allowed per zone. + # ratelimit: 0 + + # ratelimits are tracked in a cache, size in bytes of cache (or k,m). + # ratelimit-size: 4m + # ratelimit cache slabs, reduces lock contention if equal to cpucount. + # ratelimit-slabs: 4 + + # 0 blocks when ratelimited, otherwise let 1/xth traffic through + # ratelimit-factor: 10 + + # override the ratelimit for a specific domain name. + # give this setting multiple times to have multiple overrides. + # ratelimit-for-domain: example.com 1000 + # override the ratelimits for all domains below a domain name + # can give this multiple times, the name closest to the zone is used. + # ratelimit-below-domain: com 1000 + + # global query ratelimit for all ip addresses. + # feature is experimental. + # if 0(default) it is disabled, otherwise states qps allowed per ip address + # ip-ratelimit: 0 + + # ip ratelimits are tracked in a cache, size in bytes of cache (or k,m). + # ip-ratelimit-size: 4m + # ip ratelimit cache slabs, reduces lock contention if equal to cpucount. + # ip-ratelimit-slabs: 4 + + # 0 blocks when ip is ratelimited, otherwise let 1/xth traffic through + # ip-ratelimit-factor: 10 + + # Limit the number of connections simultaneous from a netblock + # tcp-connection-limit: 192.0.2.0/24 12 + + # select from the fastest servers this many times out of 1000. 0 means + # the fast server select is disabled. prefetches are not sped up. + # fast-server-permil: 0 + # the number of servers that will be used in the fast server selection. + # fast-server-num: 3 + + # Specific options for ipsecmod. unbound needs to be configured with + # --enable-ipsecmod for these to take effect. + # + # Enable or disable ipsecmod (it still needs to be defined in + # module-config above). Can be used when ipsecmod needs to be + # enabled/disabled via remote-control(below). + # ipsecmod-enabled: yes + # + # Path to executable external hook. It must be defined when ipsecmod is + # listed in module-config (above). + # ipsecmod-hook: "./my_executable" + # + # When enabled unbound will reply with SERVFAIL if the return value of + # the ipsecmod-hook is not 0. + # ipsecmod-strict: no + # + # Maximum time to live (TTL) for cached A/AAAA records with IPSECKEY. + # ipsecmod-max-ttl: 3600 + # + # Reply with A/AAAA even if the relevant IPSECKEY is bogus. Mainly used for + # testing. + # ipsecmod-ignore-bogus: no + # + # Domains for which ipsecmod will be triggered. If not defined (default) + # all domains are treated as being whitelisted. + # ipsecmod-whitelist: "example.com" + # ipsecmod-whitelist: "nlnetlabs.nl" + + +# Python config section. To enable: +# o use --with-pythonmodule to configure before compiling. +# o list python in the module-config string (above) to enable. +# It can be at the start, it gets validated results, or just before +# the iterator and process before DNSSEC validation. +# o and give a python-script to run. +python: + # Script file to load + # python-script: "/ubmodule-tst.py" + +# Remote control config section. +remote-control: + # Enable remote control with unbound-control(8) here. + # set up the keys and certificates with unbound-control-setup. + control-enable: $RC_ENABLE + + # what interfaces are listened to for remote control. + # give 0.0.0.0 and ::0 to listen to all interfaces. + # set to an absolute path to use a unix local name pipe, certificates + # are not used for that, so key and cert files need not be present. + # control-interface: 127.0.0.1 + control-interface: $RC_INTERFACE + + # port number for remote control operations. + # control-port: 8953 + + # for localhost, you can disable use of TLS by setting this to "no" + # For local sockets this option is ignored, and TLS is not used. + # control-use-cert: "yes" + + # unbound server key file. + server-key-file: "$RC_SERVER_KEY_FILE" + + # unbound server certificate file. + server-cert-file: "$RC_SERVER_CERT_FILE" + + # unbound-control key file. + control-key-file: "$RC_CONTROL_KEY_FILE" + + # unbound-control certificate file. + control-cert-file: "$RC_CONTROL_CERT_FILE" + +# Stub zones. +# Create entries like below, to make all queries for 'example.com' and +# 'example.org' go to the given list of nameservers. list zero or more +# nameservers by hostname or by ipaddress. If you set stub-prime to yes, +# the list is treated as priming hints (default is no). +# With stub-first yes, it attempts without the stub if it fails. +# Consider adding domain-insecure: name and local-zone: name nodefault +# to the server: section if the stub is a locally served zone. +# stub-zone: +# name: "example.com" +# stub-addr: 192.0.2.68 +# stub-prime: no +# stub-first: no +# stub-tls-upstream: no +# stub-no-cache: no +# stub-zone: +# name: "example.org" +# stub-host: ns.example.com. + +# Forward zones +# Create entries like below, to make all queries for 'example.com' and +# 'example.org' go to the given list of servers. These servers have to handle +# recursion to other nameservers. List zero or more nameservers by hostname +# or by ipaddress. Use an entry with name "." to forward all queries. +# If you enable forward-first, it attempts without the forward if it fails. +# forward-zone: +# name: "example.com" +# forward-addr: 192.0.2.68 +# forward-addr: 192.0.2.73@5355 # forward to port 5355. +# forward-first: no +# forward-tls-upstream: no +# forward-no-cache: no +# forward-zone: +# name: "example.org" +# forward-host: fwd.example.com + +forward-zone: + name: "." +$(generate_forward_addr) + +# Authority zones +# The data for these zones is kept locally, from a file or downloaded. +# The data can be served to downstream clients, or used instead of the +# upstream (which saves a lookup to the upstream). The first example +# has a copy of the root for local usage. The second serves example.org +# authoritatively. zonefile: reads from file (and writes to it if you also +# download it), master: fetches with AXFR and IXFR, or url to zonefile. +# With allow-notify: you can give additional (apart from masters) sources of +# notifies. +# auth-zone: +# name: "." +# master: 199.9.14.201 # b.root-servers.net +# master: 192.33.4.12 # c.root-servers.net +# master: 199.7.91.13 # d.root-servers.net +# master: 192.5.5.241 # f.root-servers.net +# master: 192.112.36.4 # g.root-servers.net +# master: 193.0.14.129 # k.root-servers.net +# master: 192.0.47.132 # xfr.cjr.dns.icann.org +# master: 192.0.32.132 # xfr.lax.dns.icann.org +# master: 2001:500:200::b # b.root-servers.net +# master: 2001:500:2::c # c.root-servers.net +# master: 2001:500:2d::d # d.root-servers.net +# master: 2001:500:2f::f # f.root-servers.net +# master: 2001:500:12::d0d # g.root-servers.net +# master: 2001:7fd::1 # k.root-servers.net +# master: 2620:0:2830:202::132 # xfr.cjr.dns.icann.org +# master: 2620:0:2d0:202::132 # xfr.lax.dns.icann.org +# fallback-enabled: yes +# for-downstream: no +# for-upstream: yes +# auth-zone: +# name: "example.org" +# for-downstream: yes +# for-upstream: yes +# zonefile: "example.org.zone" + +# Views +# Create named views. Name must be unique. Map views to requests using +# the access-control-view option. Views can contain zero or more local-zone +# and local-data options. Options from matching views will override global +# options. Global options will be used if no matching view is found. +# With view-first yes, it will try to answer using the global local-zone and +# local-data elements if there is no view specific match. +# view: +# name: "viewname" +# local-zone: "example.com" redirect +# local-data: "example.com A 192.0.2.3" +# local-data-ptr: "192.0.2.3 www.example.com" +# view-first: no +# view: +# name: "anotherview" +# local-zone: "example.com" refuse + +# DNSCrypt +# Caveats: +# 1. the keys/certs cannot be produced by unbound. You can use dnscrypt-wrapper +# for this: https://github.com/cofyc/dnscrypt-wrapper/blob/master/README.md#usage +# 2. dnscrypt channel attaches to an interface. you MUST set interfaces to +# listen on 'dnscrypt-port' with the follo0wing snippet: +# server: +# interface: 0.0.0.0@443 +# interface: ::0@443 +# +# Finally, 'dnscrypt' config has its own section. +# dnscrypt: +# dnscrypt-enable: yes +# dnscrypt-port: 443 +# dnscrypt-provider: 2.dnscrypt-cert.example.com. +# dnscrypt-secret-key: /path/unbound-conf/keys1/1.key +# dnscrypt-secret-key: /path/unbound-conf/keys2/1.key +# dnscrypt-provider-cert: /path/unbound-conf/keys1/1.cert +# dnscrypt-provider-cert: /path/unbound-conf/keys2/1.cert + +# CacheDB +# Enable external backend DB as auxiliary cache. Specify the backend name +# (default is "testframe", which has no use other than for debugging and +# testing) and backend-specific options. The 'cachedb' module must be +# included in module-config, just before the iterator module. +# cachedb: +# backend: "testframe" +# # secret seed string to calculate hashed keys +# secret-seed: "default" +# +# # For "redis" backend: +# # redis server's IP address or host name +# redis-server-host: 127.0.0.1 +# # redis server's TCP port +# redis-server-port: 6379 +# # timeout (in ms) for communication with the redis server +# redis-timeout: 100 +EOF diff --git a/type/__unbound/gencode-remote b/type/__unbound/gencode-remote new file mode 100755 index 0000000..7c271b7 --- /dev/null +++ b/type/__unbound/gencode-remote @@ -0,0 +1,16 @@ +#!/bin/sh + +UNBOUND_CERTS_DIR=/etc/unbound + +if [ -f "$__object/parameter/enable-rc" ]; then + echo "unbound-control-setup -d $UNBOUND_CERTS_DIR" + echo "chown unbound:unbound $UNBOUND_CERTS_DIR/*.pem $UNBOUND_CERTS_DIR/*.key" +fi + +cat << EOF +if pgrep unbound; then + service unbound reload +else + service unbound start +fi +EOF diff --git a/type/__unbound/man.rst b/type/__unbound/man.rst new file mode 100644 index 0000000..350f1ea --- /dev/null +++ b/type/__unbound/man.rst @@ -0,0 +1,84 @@ +cdist-type__unbound(7) +=============================== + +NAME +---- +cdist-type__ungleich_unbound - unbound server deployment for ungleich + + +DESCRIPTION +----------- +This unbound (dns resolver and cache) deployment provides DNS64 and fetch +answers from specified upstrean DNS server. This is a singleton type. + +REQUIRED PARAMETERS +------------------- +forward_addr + DNS servers used to lookup names, can be provided multiple times. It can be + either an IPv4 or IPv6 address but no domain name. + +OPTIONAL PARAMETERS +------------------- +interface + Interface to listen on, can be provided multiple times. Defaults to + '127.0.0.1' and '::1'. + +access-control + Controls which clients are allowed queries to the unbound service (everything + but localhost is refused by default), can be provided multiple times. The + format is described in unbound.conf(5). + +rc-interface + Address or path to socket used for remote control (see `--enable_control`. Defaults to `127.0.0.1`). + +local-data + Configure local data, which is served in reply to queries for it. Can be + specified multiple times. + +dns64-prefix + Enable DNS64 with specified prefix. + +BOOLEAN PARAMETERS +------------------ +disable-ip4 + Do not answer or issue queries over IPv4. Cannot be used alongside the + `--disable-ip6` flag. + +disable-ip6 + Do not answer or issue queries over IPv6. Cannot be used alongside the + `--disable-ip4` flag. + +enable-rc + Enable remote control (see `unbound-control(8)`). + +EXAMPLES +-------- + +.. code-block:: sh + + __ungleich_unbound \ + --interface '::0' \ + --dns64-prefix '2a0a:e5c0:2:10::/96' \ + --forward-addr '2a0a:e5c0:2:1::5' \ + --forward-addr '2a0a:e5c0:2:1::6' \ + --access-control '::0/0 deny' \ + --access-control '2a0a:e5c0::/29 allow' \ + --access-control '2a09:2940::/29 allow' \ + --ip6 + +SEE ALSO +-------- +- `unbound.conf(5) `_ + + +AUTHORS +------- +Timothée Floure + + +COPYING +------- +Copyright \(C) 2020 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/type/__unbound/manifest b/type/__unbound/manifest new file mode 100755 index 0000000..1a23328 --- /dev/null +++ b/type/__unbound/manifest @@ -0,0 +1,105 @@ +#!/bin/sh -e +# +# 2020 Timothée Floure (timothee.floure@ungleich.ch) +# +# 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 . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + alpine) + __package unbound --state present + ;; + *) + printf "Your operating system (%s) is currently not supported by this type (%s)\n" "$os" "${__type##*/}" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# Required parameters: +FORWARD_ADDRS=$(cat "$__object/parameter/forward-addr") +export FORWARD_ADDRS + +# Optional parameters: +if [ -f "$__object/parameter/dns64-prefix" ]; then + DNS64_PREFIX=$(cat "$__object/parameter/dns64-prefix") + export DNS64_PREFIX +fi + +if [ -f "$__object/parameter/interface" ]; then + INTERFACES=$(cat "$__object/parameter/interface") + export INTERFACES +fi + +if [ -f "$__object/parameter/access-control" ]; then + ACCESS_CONTROLS=$(cat "$__object/parameter/access-control") + export ACCESS_CONTROLS +fi + +if [ -f "$__object/parameter/rc-interface" ]; then + RC_INTERFACE=$(cat "$__object/parameter/rc-interface") + export RC_INTERFACE +fi + +if [ -f "$__object/parameter/local-data" ]; then + LOCAL_DATA=$(cat "$__object/parameter/local-data") + export LOCAL_DATA +fi + +# Boolean parameters: +if [ -f "$__object/parameter/disable-ip4" ] && \ + [ -f "$__object/parameter/disable-ip6" ]; then + echo "--disable-ip4 and --disable-ip6 cannot be used at the same time." >&2 + exit 1 +fi + +if [ -f "$__object/parameter/disable-ip4" ]; then + export DO_IP4='no' +else + export DO_IP4='yes' +fi + +if [ -f "$__object/parameter/disable-ip6" ]; then + export DO_IP6='no' +else + export DO_IP6='yes' +fi + +if [ -f "$__object/parameter/enable-rc" ]; then + export RC_ENABLE='yes' +else + export RC_ENABLE='no' +fi + +# Certs for remote control: +export RC_SERVER_KEY_FILE='/etc/unbound/unbound_server.key' +export RC_SERVER_CERT_FILE='/etc/unbound/unbound_server.pem' +export RC_CONTROL_KEY_FILE='/etc/unbound/unbound_control.key' +export RC_CONTROL_CERT_FILE='/etc/unbound/unbound_control.pem' + +# Generate and deploy configuration files. +source_file="$__object/files/unbound.conf" +target_file="/etc/unbound/unbound.conf" + +mkdir -p "$__object/files" +"$__type/files/unbound.conf.sh" > "$source_file" +require="__package/unbound" __file "$target_file" \ + --source "$source_file" \ + --owner root \ + --mode 644 diff --git a/type/__unbound/parameter/boolean b/type/__unbound/parameter/boolean new file mode 100644 index 0000000..f754fa2 --- /dev/null +++ b/type/__unbound/parameter/boolean @@ -0,0 +1,3 @@ +disable-ip6 +disable-ip4 +enable-rc diff --git a/type/__unbound/parameter/default/rc-interface b/type/__unbound/parameter/default/rc-interface new file mode 100644 index 0000000..7b9ad53 --- /dev/null +++ b/type/__unbound/parameter/default/rc-interface @@ -0,0 +1 @@ +127.0.0.1 diff --git a/type/__unbound/parameter/optional b/type/__unbound/parameter/optional new file mode 100644 index 0000000..86a4400 --- /dev/null +++ b/type/__unbound/parameter/optional @@ -0,0 +1 @@ +rc-interface diff --git a/type/__unbound/parameter/optional_multiple b/type/__unbound/parameter/optional_multiple new file mode 100644 index 0000000..4d06e03 --- /dev/null +++ b/type/__unbound/parameter/optional_multiple @@ -0,0 +1,3 @@ +access-control +local-data +interface diff --git a/type/__unbound/parameter/required_multiple b/type/__unbound/parameter/required_multiple new file mode 100644 index 0000000..74b99a2 --- /dev/null +++ b/type/__unbound/parameter/required_multiple @@ -0,0 +1 @@ +forward-addr diff --git a/type/__unbound/singleton b/type/__unbound/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__unbound_exporter/files/openrc-service b/type/__unbound_exporter/files/openrc-service new file mode 100644 index 0000000..6caed5e --- /dev/null +++ b/type/__unbound_exporter/files/openrc-service @@ -0,0 +1,12 @@ +#!/sbin/openrc-run + +name=$RC_SVCNAME +command="/usr/local/bin/unbound_exporter" +command_args="" +command_user="unbound" +command_background="yes" +pidfile="/var/run/$RC_SVCNAME.pid" + +depend() { + need unbound +} diff --git a/type/__unbound_exporter/gencode-remote b/type/__unbound_exporter/gencode-remote new file mode 100755 index 0000000..fcd85fb --- /dev/null +++ b/type/__unbound_exporter/gencode-remote @@ -0,0 +1,46 @@ +#!/bin/sh -e +# +# 2020 Timothée Floure (timothee.floure@ungleich.ch) +# +# 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 . + +upstream=https://github.com/wish/unbound_exporter/archive +version=$(cat "$__object/parameter/version") +release="unbound_exporter-$version" + +cat << EOF +if command -v unbound_exporter +then + # already installed - ignoring. + echo "Nothing to do -" +else + # Initialize working directory + workdir=\$(mktemp -d) + cd \$workdir + + # Download and extract sources for requested release. + curl -L $upstream/v$version.tar.gz --output $release.tar.gz + tar xf $release.tar.gz + + # Build and install binary. + cd $release + go build + install -m755 unbound_exporter /usr/local/bin/ + + # Clean up! + rm -r \$workdir +fi +EOF diff --git a/type/__unbound_exporter/man.rst b/type/__unbound_exporter/man.rst new file mode 100644 index 0000000..934bdd7 --- /dev/null +++ b/type/__unbound_exporter/man.rst @@ -0,0 +1,63 @@ +cdist-type__unbound_exporter(7) +=============================== + +NAME +---- +cdist-type__unbound_exporter - A prometheus exporter for unbound + + +DESCRIPTION +----------- +Simple Prometheus metrics exporter for the Unbound DNS +resolver. It leverages the unbound remote control endpoint +and exposes metrics on port 9167. + + +REQUIRED PARAMETERS +------------------- +version + unbound_exporter release to be used. + +OPTIONAL PARAMETERS +------------------- +None. + + +BOOLEAN PARAMETERS +------------------ +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + __unbound \ + --interface '::0' \ + --forward_addr '2a0a:e5c0:2:1::5' \ + --forward_addr '2a0a:e5c0:2:1::6' \ + --access_control '::0/0 deny' \ + --access_control '2a0a:e5c0::/29 allow' \ + --access_control '2a09:2940::/29 allow' \ + --disable_ip4 \ + --enable_rc \ + --rc_interface '::1' + + __unbound_exporter --version 0.1.3 + +SEE ALSO +-------- +:strong:`cdist-type__unbound(7)` + +AUTHORS +------- +Timothée Floure + + +COPYING +------- +Copyright \(C) 2020 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/type/__unbound_exporter/manifest b/type/__unbound_exporter/manifest new file mode 100755 index 0000000..3602e47 --- /dev/null +++ b/type/__unbound_exporter/manifest @@ -0,0 +1,45 @@ +#!/bin/sh -e +# +# 2020 Timothée Floure (timothee.floure@ungleich.ch) +# +# 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 . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + alpine) + # Used in gencode-remote. + __package curl + __package tar + __package openssl + __package go + __package libc-dev + ;; + *) + printf "Your operating system (%s) is currently not supported by this type (%s)\n" "$os" "${__type##*/}" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +__file /etc/init.d/unbound_exporter \ + --source "$__type/files/openrc-service" \ + --mode 755 + +require="__file/etc/init.d/unbound_exporter" __service unbound_exporter --action start +require="__file/etc/init.d/unbound_exporter" __start_on_boot unbound_exporter diff --git a/type/__unbound_exporter/parameter/required b/type/__unbound_exporter/parameter/required new file mode 100644 index 0000000..088eda4 --- /dev/null +++ b/type/__unbound_exporter/parameter/required @@ -0,0 +1 @@ +version diff --git a/type/__unbound_exporter/singleton b/type/__unbound_exporter/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__wikijs/files/config.yml.sh b/type/__wikijs/files/config.yml.sh new file mode 100755 index 0000000..b66687a --- /dev/null +++ b/type/__wikijs/files/config.yml.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +if [ $# -ne 1 ]; +then + echo "You have to give me the database password as an argument:" + echo "on some systems, anyone can read env(1)." + exit 1; +fi + +generate_ssl_section () { + + cat << EOF +ssl: + enabled: ${SSL} +EOF + +if [ "$SSL" = "true" ]; then + cat << EOF + port: $HTTPS_PORT + provider: letsencrypt + domain: ${__target_host:?} + subscriberEmail: ${LE_EMAIL:?} +EOF + fi +} + +cat << EOF +port: $HTTP_PORT +db: + type: postgres + host: localhost + port: 5432 + user: ${DB_USER:?} + pass: $1 + db: ${DB_NAME:?} + ssl: false +$(generate_ssl_section) +pool: + min: 2 + max: 10 +bindIP: 0.0.0.0 +logLevel: warn +offline: false +ha: false +dataPath: ./data +EOF diff --git a/type/__wikijs/files/wikijs-openrc b/type/__wikijs/files/wikijs-openrc new file mode 100644 index 0000000..e484647 --- /dev/null +++ b/type/__wikijs/files/wikijs-openrc @@ -0,0 +1,10 @@ +#!/sbin/openrc-run + +command='/usr/bin/node' +command_args='server' +command_background=true +description="Run wiki.js" +directory='/var/wiki' +error_log=/var/log/"$RC_SVCNAME".err +output_log=/var/log/"$RC_SVCNAME".log +pidfile="/run/$RC_SVCNAME.pid" diff --git a/type/__wikijs/gencode-remote b/type/__wikijs/gencode-remote new file mode 100755 index 0000000..37c7df7 --- /dev/null +++ b/type/__wikijs/gencode-remote @@ -0,0 +1,26 @@ +#!/bin/sh + +VERSION_FILE=/var/wiki/version +version=$(cat "${__object:?}/parameter/version") + +# Check for installation +cat << EOF +if [ -f $VERSION_FILE ] && [ "\$(cat $VERSION_FILE)" = "$version" ]; +then + # Assume everything is done already. + exit 0; +else + echo "$version" > $VERSION_FILE +fi +EOF + +# Download and copy source +cat << EOF +wget -O - https://github.com/Requarks/wiki/releases/download/$version/wiki-js.tar.gz | tar xz -C /var/wiki +EOF + +# Install deps and launch +cat << EOF +cd /var/wiki || exit 1 +service wikijs restart +EOF diff --git a/type/__wikijs/man.rst b/type/__wikijs/man.rst new file mode 100644 index 0000000..b259c90 --- /dev/null +++ b/type/__wikijs/man.rst @@ -0,0 +1,64 @@ +cdist-type__wikijs(7) +======================== + +NAME +---- +cdist-type__wikijs - Deploy the wiki.js software. + +DESCRIPTION +----------- + +See wiki.js.org for more information. This type deploys with a postgresql +database, since it is the upstream recommended for production, and they seem to +strongly suggest that in the next releases, they will not support anything else. + +Currently, this type servers wikijs as standalone, listening on ports 80 and +443, and with a service file for OpenRC. Feel free to contribute a +generalisation if you require one. + +REQUIRED PARAMETERS +------------------- + +database-password + The password to the PSQL database. + +version + 'wikijs' version to be deployed. + +OPTIONAL PARAMETERS +------------------- + +database + The name of the PSQL database to connect to. If omitted, then 'wikijs' is + used. + +database-user + The name of the PSQL database user to connec as. If omitted, then 'wikijs' is + used. + +letsencrypt-mail + If the SSL parameter is passed, then we setup wikijs to automatically obtain + certificates: this is the email used to sign up to a LE account. + +http-port + Specify HTTP port, defaults to 80. + +http-port + Specify HTTPS port, defaults to 443. Only relevant if the SSL flag is enabled. + +BOOLEAN PARAMETERS +------------------ + +ssl + Whether or not to enable the wikijs automatic obtention of LE certificates. + +AUTHORS +------- +Joachim Desroches + +COPYING +------- +Copyright \(C) 2020 Joachim Desroches. 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/type/__wikijs/manifest b/type/__wikijs/manifest new file mode 100644 index 0000000..b047223 --- /dev/null +++ b/type/__wikijs/manifest @@ -0,0 +1,64 @@ +#!/bin/sh + +os="$(cat "${__global:?}"/explorer/os)" + +case "$os" in + alpine) + : + ;; + *) + echo "This type has no implementation for $os. Aborting." >&2; + exit 1; +esac + +DB_USER=wikijs +if [ -f "${__object:?}/parameter/database-user" ]; +then + DB_USER="$(cat "${__object:?}/parameter/database-user")" +fi +export DB_USER + +DB_NAME=wikijs +if [ -f "${__object:?}/parameter/database" ]; +then + DB_NAME="$(cat "${__object:?}/parameter/database")" +fi +export DB_NAME + +SSL=false +if [ -f "${__object:?}/parameter/ssl" ]; +then + SSL=true +fi +export SSL + +if [ "$SSL" = "true" ]; +then + if [ -f "${__object:?}/parameter/letsencrypt-mail" ]; + then + LE_EMAIL="$(cat "${__object:?}/parameter/letsencrypt-mail")" + export LE_EMAIL + else + echo "You must specify an email account if you request SSL." + echo "Hit me." + exit 1 + fi +fi + +HTTP_PORT=$(cat "${__object:?}/parameter/http-port") +HTTPS_PORT=$(cat "${__object:?}/parameter/https-port") +export HTTP_PORT HTTPS_PORT + +db_pass="$(cat "${__object:?}/parameter/database-password")" + +__package nodejs +__directory /var/wiki/ + +# These things are Alpine-dependant. +__file /etc/init.d/wikijs --source "${__type:?}/files/wikijs-openrc" +__package nghttp2-dev # Required for some reason, else a symbol is missing + +mkdir -p "${__object:?}/files" +"${__type:?}/files/config.yml.sh" "$db_pass" > "${__object:?}/files/config.yml" +require='__directory/var/wiki' \ + __file /var/wiki/config.yml --source "${__object:?}/files/config.yml" diff --git a/type/__wikijs/parameter/boolean b/type/__wikijs/parameter/boolean new file mode 100644 index 0000000..a2647ce --- /dev/null +++ b/type/__wikijs/parameter/boolean @@ -0,0 +1 @@ +ssl diff --git a/type/__wikijs/parameter/default/http-port b/type/__wikijs/parameter/default/http-port new file mode 100644 index 0000000..d15a2cc --- /dev/null +++ b/type/__wikijs/parameter/default/http-port @@ -0,0 +1 @@ +80 diff --git a/type/__wikijs/parameter/default/https-port b/type/__wikijs/parameter/default/https-port new file mode 100644 index 0000000..6a13cf6 --- /dev/null +++ b/type/__wikijs/parameter/default/https-port @@ -0,0 +1 @@ +443 diff --git a/type/__wikijs/parameter/optional b/type/__wikijs/parameter/optional new file mode 100644 index 0000000..be19c92 --- /dev/null +++ b/type/__wikijs/parameter/optional @@ -0,0 +1,5 @@ +database +database-user +letsencrypt-mail +http-port +https-port diff --git a/type/__wikijs/parameter/required b/type/__wikijs/parameter/required new file mode 100644 index 0000000..ae542bc --- /dev/null +++ b/type/__wikijs/parameter/required @@ -0,0 +1,2 @@ +database-password +version diff --git a/type/__wikijs/singleton b/type/__wikijs/singleton new file mode 100644 index 0000000..e69de29