Initial checkin

remotes/origin/master 0.16.0
Michael Prokop 12 years ago
commit 3436c08361

@ -0,0 +1,59 @@
# for syntax checks
BASH_SCRIPTS = scripts/* functions/* etc/ngcp-config/ngcpcfg.cfg helper/build_config sbin/ngcpcfg
PERL_SCRIPTS = helper/sort-yml \
helper/sync-db \
helper/tt2-wrapper \
helper/validate-yml helper/fileformat_version \
sbin/ngcp-network \
sbin/ngcp-sync-constants
all: docs
docs: html pdf epub man
html:
asciidoc docs/ngcpcfg.txt
pdf:
a2x --icons -a toc -a toclevels=3 -a docinfo -f pdf docs/ngcpcfg.txt
epub:
a2x --icons -a toc -a toclevels=3 -a docinfo -f epub docs/ngcpcfg.txt
man:
asciidoc -d manpage -b docbook docs/ngcpcfg.txt
sed -i 's/<emphasis role="strong">/<emphasis role="bold">/' docs/ngcpcfg.xml
xsltproc --nonet /usr/share/xml/docbook/stylesheet/nwalsh/manpages/docbook.xsl docs/ngcpcfg.xml
pod2man --section=8 sbin/ngcp-network > ngcp-network.8
pod2man --section=8 sbin/ngcp-sync-constants > ngcp-sync-constants.8
clean:
rm -f docs/ngcpcfg.xml docs/ngcpcfg.epub docs/ngcpcfg.html docs/ngcpcfg.pdf
rm -f ngcpcfg.8 ngcp-network.8 ngcp-sync-constants.8
dist-clean:
rm -f docs/ngcpcfg.html docs/ngcpcfg.pdf
rm -f docs/ngcpcfg.epub ngcpcfg.8
# check for syntax errors
syntaxcheck: shellcheck perlcheck
shellcheck:
@echo -n "Checking for shell syntax errors"; \
for SCRIPT in $(BASH_SCRIPTS); do \
test -r $${SCRIPT} || continue ; \
bash -n $${SCRIPT} || exit ; \
echo -n "."; \
done; \
echo " done."; \
perlcheck:
@echo "Checking for perl syntax errors:"; \
for SCRIPT in $(PERL_SCRIPTS); do \
test -r $${SCRIPT} || continue ; \
perl -CSD -w -c $${SCRIPT} || exit ; \
done; \
echo "-> perl check done."; \
# EOF

357
debian/changelog vendored

@ -0,0 +1,357 @@
ngcp-ngcpcfg (0.16.0) unstable; urgency=low
* New release splitting of ha/carrier features.
-- Michael Prokop <mprokop@sipwise.com> Wed, 13 Mar 2013 14:21:25 +0100
ngcp-ngcpcfg (0.15.3) unstable; urgency=low
* ngcp-sync-constants takes MySQL credentials from /etc/mysql/sipwise.cnf
-- Kirill Solomko <ksolomko@sipwise.com> Wed, 15 Jan 2013 16:32:11 +0100
ngcp-ngcpcfg (0.15.2) unstable; urgency=low
* Fix sync for asterisk ODBC credentials.
-- Andrew Pogrebennyk <apogrebennyk@sipwise.com> Wed, 02 Jan 2013 11:27:23 +0100
ngcp-ngcpcfg (0.15.1) unstable; urgency=low
* Make sure to sync both sems and sems_prepaid passwords.
-- Andrew Pogrebennyk <apogrebennyk@sipwise.com> Fri, 21 Dec 2012 21:47:51 +0100
ngcp-ngcpcfg (0.15.0) unstable; urgency=low
* Implement ngcp-network command-line tool.
* Implement ngcp-ngcpcfg-carrier package.
* Add helper functions for network.yml transition.
* support configuration directory /etc/ngcp-config/ngcpcfg.d
* provide carton/cpanfile integration for running testsuite on Jenkins
* Check the fax_gateways defined or not
* Add support to netmask for the fax_gateways
-- Andrew Pogrebennyk <apogrebennyk@sipwise.com> Fri, 21 Dec 2012 11:27:15 +0100
ngcp-ngcpcfg (0.14.1) unstable; urgency=low
[ mwang ]
* sync-db: Check the fax_gateways defined or not
-- Jon Bonilla <jbonilla@sipwise.com> Wed, 22 Aug 2012 12:50:01 +0200
ngcp-ngcpcfg (0.14.0) unstable; urgency=low
[ Michael Prokop ]
* Adjust configuration file handling to properly work with UTF-8 input
* Run etckeeper when invoking "ngcpcfg commit"
* Adjust detection of new configuration files that are not yet tracked
* Bump Standards-Version to 3.9.3
* etckeeper: check for etckeeper binary and initialised .git repo
* commit: do not exit on errors during sync-db
* services option: run inside a function so --dry-run option works
correct
* wrap and sort items in Debian packaging files
[ Andreas Granig ]
* On commit, also sync various options with db using helper/sync-db
[ Min Wang ]
* helper/sync-db related changes:
- Add sync fax_gateways for kamailio dispatcher table
- Add reloading dispatcher once fax_gateways changes
- Print out the reload dispatcher return status
-- Michael Prokop <mprokop@sipwise.com> Fri, 10 Aug 2012 18:33:19 +0200
ngcp-ngcpcfg (0.13.1) unstable; urgency=low
* Do not rely on TTL but instead use timeout when checking other host(s)
* pull: no need to run fetch check in subshell
* pull: avoid diverging branches if changes take place on both sides.
Thanks to Andrew Pogrebennyk for catching the bug + providing
instructions to reproduce it
* pull: exit with return code of pull command
-- Michael Prokop <mprokop@sipwise.com> Mon, 14 May 2012 15:27:05 +0200
ngcp-ngcpcfg (0.13.0) unstable; urgency=low
[ Michael Prokop ]
* Install ngcpcfg manpage in main ngcp-ngcpcfg package
[ Andrew Pogrebennyk ]
* Add yml upgrade scripts for 2.5
* Add testfiles for 2.5 ce and pro
* Add yml update helper scripts
-- Michael Prokop <mprokop@sipwise.com> Tue, 03 Apr 2012 16:24:30 +0200
ngcp-ngcpcfg (0.12.4) unstable; urgency=low
[ Michael Prokop ]
* perlcheck: invoke perl with -CSD option
-- Michael Prokop <mprokop@sipwise.com> Thu, 26 Jan 2012 17:38:19 +0100
ngcp-ngcpcfg (0.12.3) unstable; urgency=low
[ Richard Fuchs ]
* Fix handling of utf8 files
[ Michael Prokop ]
* Config builder: do not output error message, provide
debugging instructions instead
-- Michael Prokop <mprokop@sipwise.com> Thu, 26 Jan 2012 16:51:51 +0100
ngcp-ngcpcfg (0.12.2) unstable; urgency=low
* provide force-reload in ngcpcfg-status init script
* diff command: drop --addremove option and make it the
default behaviour
-- Michael Prokop <mprokop@sipwise.com> Thu, 26 Jan 2012 12:36:56 +0100
ngcp-ngcpcfg (0.12.1) unstable; urgency=low
* upgrade scripts:
- update internal file format information
- bump fileversion of cdrexport to 003
-- Michael Prokop <mprokop@sipwise.com> Fri, 02 Dec 2011 22:23:58 +0100
ngcp-ngcpcfg (0.12.0) unstable; urgency=low
[ Michael Prokop ]
* Add simple sort-file script for easier comparison of upgrade script output
* Provide upgrade scripts for recent sip:provider releases
* Update configuration files according to recent development
* Add fileformat_version helper script for usage inside upgrade scripts
* Error out if encoding of a central configuration file isn't ASCII nor UTF-8
* tt2-wrapper: explicitely set utf8 mode for stdout
* Run xsltproc with --nonet option
* Add config.yml/constants.yml testfiles for new sip:provider releases
[ Jon Bonilla ]
* Adapt upgrade scripts to recent development
* Adapt testfile to recent development
-- Michael Prokop <mprokop@sipwise.com> Tue, 29 Nov 2011 17:49:45 +0100
ngcp-ngcpcfg (0.11.1) unstable; urgency=low
* Bugfixes:
- ngcpcfg: fix usage instructions regarding --debug switch
* Debian packaging:
- rework debian/rules to use generic rule to build packages
- use team as entry in Maintainer field of debian/control
* Testsuite improvements:
- test tt2 processing + precedence of files
- validate ngcpcfg without any arguments, with --version
and with --help
* High Availability Setup:
- pull: add further debug statements
- push: use 'ngcpcfg apply' in default action and support
--noapply for disabling the behaviour
- push: use ngcpcfg pull instead of native git commands
- push: if ssh login does not work report it with specific
error message
-- Michael Prokop <mprokop@sipwise.com> Thu, 22 Sep 2011 01:34:04 +0200
ngcp-ngcpcfg (0.11.0) unstable; urgency=low
* Bugfixes:
- Do not strip $CONFIG_POOL variable from provided file/directory
arguments when generating file list
- Get rid of files *.tt2.sp{1,2} where a *.customtt.tt2.sp{1,2}
exists as well
* New features:
- Build option: support generation of modified files only when
using --modified-only option
- Diff: support --addremove option to list new/removed files
- Provide version information through -v, --version + version options
- Push: be more verbose when operation fails
- Services: support --dry-run as alternative to 'test' option,
error out on unknown options
- Support --debug option to run actions in debug mode
- Support new option "diff" to show pending modifications in
configuration pool
* Improvements:
- Do not remove temporary filelist files in debug mode
- Extend package description of ngcp-ngcpcfg-ha
- Redesign code for generating the file list
- Update ngcpcfg manpage (document new options, clarify
precedence of configuration files,...)
* High Availability Setup:
- Do not add host to host list if build operation was successfull
- Fix typo in warning message (registerted<->registered)
- Support --nobuild option to skip build process when pushing
changes
- When pushing changes then execute 'build' on all pushed hosts
-- Michael Prokop <mprokop@sipwise.com> Mon, 29 Aug 2011 13:42:23 +0200
ngcp-ngcpcfg (0.10.0) unstable; urgency=low
* Add further logic and user information for validating YAML syntax.
* Make sure customtt.tt2 template files are preferred over
non-customtt.tt2 files in non-HA setups.
* encrypt/decrypt: get rid of ngcpcfg-share on glusterfs and
local cache on encrypt and try to restore it iff possible or otherwis
* Fix unset variable if calling ngcpcfg without any options
and having ngcpcfg-locker installed.
* Usage text: correctly indent optional features.
* Add build-arch/build-indep targets to debian/rules to make lintian happy.
* Drop essential package tar from Depends of ngcp-ngcpcfg-locker.
* Drop essential package bsdutils from Depends.
-- Michael Prokop <mprokop@sipwise.com> Sat, 20 Aug 2011 00:20:34 +0200
ngcp-ngcpcfg (0.9.0) unstable; urgency=low
* Before generating new configuration files from templates
test known .yml files for valid syntax.
* New package ngcp-ngcpcfg-locker: support encrypting/decrypting
ngcpcfg configuration files.
* Initial version of an upgrade script to support safe upgrades.
-- Michael Prokop <mprokop@sipwise.com> Mon, 04 Jul 2011 15:49:36 +0200
ngcp-ngcpcfg (0.8.0) unstable; urgency=low
[ Michael Prokop ]
* Adjust package description.
* Upgrade script:
- Add clir and block-override VSC.
- Add www_admin.peer with preference_features flag.
- Add preference_features switch for domains in www-admin.
* Fix gitignore configuration of ngcpcfg.
* Bump Standards-Version to 3.9.2.
* HA features:
- Store node name in /etc/ngcp_ha_node.
- Use glusterfs share as default remote target and make setup
consistent between involved nodes.
[ Andreas Granig ]
* Aligned to x.y.z versioning scheme.
-- Michael Prokop <mprokop@sipwise.com> Sat, 11 Jun 2011 01:44:46 +0200
ngcp-ngcpcfg (0.7.0) unstable; urgency=low
[ Michael Prokop ]
* Bugfix:
- Make sure we switch to $NGCPCTL_MAIN before marking host as
initialised.
* Features:
- Support shared setup (via ngcp-ngcpcfg-ha).
- Support .sp1 and .sp2 files for shared setup (ngcp-ngcpcfg-ha).
- Provide debugging option through environment variable DEBUG.
- Send status messages to syslog.
- Check for Debian package versions of templates on all nodes and do
NOT push in case of different package versions (applies only
to files that are going to be pushed and not to all templates,
ngcp-ngcpcfg-ha only).
- Provide upgrade package ngcp-ngcpcfg-upgrade to apply schema
changes when upgrading from 2.1 to 2.2.
- Support {pre,post}build scripts within template directory.
- Initial testsuite to check for regressions.
- Provide validate-yml script to validate configuration file.
- Provide sort-yml script to sort configuration file for easier
comparison with other configuration files.
- Provide warning message if a service script did not return
with exit code 0.
- Support {pre,post}build scripts within template directory.
* Changes:
- Refactor code to minimise user interface script and provide
options (build/commit/...) through separate scripts.
- Drop HELPER configuration variable from ngcpcfg.cfg.
- Slightly improve /etc/ngcp-config/ngcpcfg.cfg (description and
sorting of variables.
* Debian packaging:
- Drop shlibs:Depends from Depends, we do not have any libraries.
- Fix typo in long description.
- Add debian/source/format (1.0 format).
- Provide syntaxchecks for bash and perl scripts as Q/A mechanism
in build process.
- Add perl packages to Build-Depends.
- Drop unnecessary libtemplate-plugin-yaml-perl from Depends.
- Run syntax checks for code while building, therefore add
libhash-merge-perl, libtemplate-perl and libyaml-perl to
Build-Depends.
[ Richard Fuchs ]
* Add libyaml-tiny-perl to Build-Depends.
[ Jon Bonilla ]
* Add support to ngcpcfg.{pre|post}build directory generic files.
-- Andreas Granig <agranig@sipwise.com> Fri, 29 Apr 2011 12:10:13 +0200
ngcp-ngcpcfg (0.6) unstable; urgency=low
[ Jon Bonilla ]
* Add constants.yaml file handling so the user can configure
just configurable options.
[ Andreas Granig ]
* Added "apply" as a short-cut for build, then services, then commit.
[ Michael Prokop ]
* Iff a directory does not exist yet create it with permissions 755.
* Update stderr printf handling.
* Integrate etckeeper commit in "apply" shortcut.
* Update copyright (GPL-3+).
* Work around a git index issue with generated files for use with
the service command.
-- Michael Prokop <mprokop@sipwise.com> Tue, 30 Nov 2010 11:52:19 +0100
ngcp-ngcpcfg (0.5) unstable; urgency=low
* Support .prebuild and .postbuild scripts inside template pool
which are executre before/after generation of output file.
* Support building of specific files/directories only so it's
possible to execute e.g. 'ngcpcfg build /etc/apache2' to
skip generation of any files besides the ones inside /etc/apache2.
-- Michael Prokop <mprokop@sipwise.com> Tue, 16 Nov 2010 18:27:28 +0100
ngcp-ngcpcfg (0.4) unstable; urgency=low
* Support additional config.local.yml config file.
* Support .customtt.tt2 files for local configuration.
* Provide service files through same directory as templates.
* Unify service executions.
* Make generated files r/o.
* Inform if config has changed and is not "build" yet.
* Show which files have been modified.
-- Michael Prokop <mprokop@sipwise.com> Wed, 10 Nov 2010 13:04:56 +0100
ngcp-ngcpcfg (0.3) unstable; urgency=low
* Unify directory names, configuration files,...
-- Michael Prokop <mprokop@sipwise.com> Wed, 20 Oct 2010 14:03:01 +0200
ngcp-ngcpcfg (0.2) unstable; urgency=low
* Support non-shared setup.
-- Michael Prokop <mprokop@sipwise.com> Tue, 12 Oct 2010 18:02:10 +0200
ngcp-ngcpcfg (0.1) unstable; urgency=low
* Initial release.
-- Michael Prokop <mprokop@sipwise.com> Thu, 26 Aug 2010 17:19:32 +0200

1
debian/compat vendored

@ -0,0 +1 @@
5

60
debian/control vendored

@ -0,0 +1,60 @@
Source: ngcp-ngcpcfg
Section: admin
Priority: extra
Maintainer: Sipwise Development Team <support@sipwise.com>
Build-Depends: asciidoc,
debhelper (>= 5),
docbook-xsl,
libdata-validate-ip-perl,
libdbd-mysql-perl,
libhash-merge-perl,
libio-interface-perl,
liblist-moreutils-perl,
libnet-netmask-perl,
libregexp-ipv6-perl,
libtemplate-perl,
libyaml-perl,
libyaml-tiny-perl,
xsltproc
Standards-Version: 3.9.4
Homepage: http://sipwise.com/
Package: ngcp-ngcpcfg
Architecture: all
Depends: etckeeper,
file,
git-core,
libdata-validate-ip-perl,
libdbd-mysql-perl,
libhash-merge-perl,
libio-interface-perl,
liblist-moreutils-perl,
libnet-netmask-perl,
libregexp-ipv6-perl,
libtemplate-perl,
libyaml-perl,
libyaml-tiny-perl,
${misc:Depends},
${perl:Depends}
Description: central and templated based Configuration Management System for NGCP platforms
ngcp-ngcpcfg is a Configuration Management System providing central
configuration and template based handling of configuration
files, featuring handling of local configuration changes and
updates as well as synchronisation between servers.
Package: ngcp-ngcpcfg-locker
Architecture: all
Depends: gnupg,
ngcp-ngcpcfg,
${misc:Depends}
Description: Encrypt and decrypt feature for ngcp-ngcpcfg
This package provides the encrypt and decrypt options for
usage via ngcpcfg.
Package: ngcp-ngcpcfg-testsuite
Architecture: all
Depends: ngcp-ngcpcfg,
${misc:Depends}
Description: testsuite for ngcpcfg
This package provides a testsuite to automatically test ngcpcfg
features and detect any possible breakages.

23
debian/copyright vendored

@ -0,0 +1,23 @@
Upstream Author: The Sipwise Team - http://sipwise.com
Copyright: 2007-2013, Sipwise GmbH, Austria
License: GPL-3+
This program is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later
version.
.
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the GNU General Public License for more
details.
.
You should have received a copy of the GNU General Public
License along with this package; if not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301 USA
.
On Debian systems, the full text of the GNU General Public
License version 3 can be found in the file
`/usr/share/common-licenses/GPL-3'.

@ -0,0 +1,2 @@
scripts/decrypt usr/share/ngcp-ngcpcfg/scripts/
scripts/encrypt usr/share/ngcp-ngcpcfg/scripts/

@ -0,0 +1 @@
testsuite/* usr/share/ngcp-ngcpcfg/testsuite/

@ -0,0 +1,19 @@
etc/ngcp-config/ngcpcfg.cfg etc/ngcp-config/
functions/main usr/share/ngcp-ngcpcfg/functions/
helper/build_config usr/share/ngcp-ngcpcfg/helper/
helper/fileformat_version usr/share/ngcp-ngcpcfg/helper/
helper/sort-yml usr/share/ngcp-ngcpcfg/helper/
helper/sync-db usr/share/ngcp-ngcpcfg/helper/
helper/tt2-wrapper usr/share/ngcp-ngcpcfg/helper/
helper/validate-yml usr/share/ngcp-ngcpcfg/helper/
lib/* usr/lib/ngcp-ngcpcfg/
sbin/ngcp-network usr/sbin/
sbin/ngcpcfg usr/sbin/
sbin/ngcp-sync-constants usr/sbin/
scripts/build usr/share/ngcp-ngcpcfg/scripts/
scripts/commit usr/share/ngcp-ngcpcfg/scripts/
scripts/diff usr/share/ngcp-ngcpcfg/scripts/
scripts/etckeeper usr/share/ngcp-ngcpcfg/scripts/
scripts/initialise usr/share/ngcp-ngcpcfg/scripts/
scripts/services usr/share/ngcp-ngcpcfg/scripts/
scripts/status usr/share/ngcp-ngcpcfg/scripts/

@ -0,0 +1,3 @@
ngcpcfg.8
ngcp-network.8
ngcp-sync-constants.8

31
debian/postinst vendored

@ -0,0 +1,31 @@
#!/bin/sh
# postinst script for ngcp-ngcpcfg
set -e
case "$1" in
configure)
if ! [ -d /etc/.git ] ; then
cd /etc
etckeeper init
git rm --cached -r ngcp-config || true
grep -q '^ngcp-config$' .gitignore || echo 'ngcp-config' >> .gitignore
git commit -a -m "initial commit"
fi
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

68
debian/rules vendored

@ -0,0 +1,68 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
# export DH_VERBOSE=1
b=$(CURDIR)/debian/build
VERSION:=$(shell dpkg-parsechangelog | awk '/Version: / { print $$2 }')
build: build-stamp
build-stamp:
dh_testdir
$(MAKE) man
# catch any syntax errors *before* building the .deb
$(MAKE) syntaxcheck
touch $@
clean:
dh_testdir
dh_testroot
rm -rf build-stamp $(b)
dh_auto_clean
dh_clean
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
%:
@echo "--- Building: $@"
dh_installdirs -p$@ -P$(b)/$@
dh_link -p$@ -P$(b)/$@
dh_installdocs -p$@ -P$(b)/$@
dh_installman -p$@ -P$(b)/$@
dh_installchangelogs -p$@ -P$(b)/$@
dh_install -p$@ -P$(b)/$@
test -r $(b)/$@/usr/sbin/ngcp-network && \
sed -i -e "s/VERSION = 'UNRELEASED'/VERSION = '$(VERSION)'/" \
$(b)/$@/usr/sbin/ngcp-network || true
dh_link -p$@ -P$(b)/$@
dh_strip -p$@ -P$(b)/$@
dh_compress --exclude=examples/etc/ --exclude=packages/ -p$@ -P$(b)/$@
dh_fixperms -p$@ -P$(b)/$@
dh_makeshlibs -p$@ -P$(b)/$@ -V
dh_installdeb -p$@ -P$(b)/$@
dh_shlibdeps -p$@ -P$(b)/$@
dh_installdebconf -p$@ -P$(b)/$@
dh_gencontrol -p$@ -P$(b)/$@
dh_md5sums -p$@ -P$(b)/$@
dh_builddeb -p$@ -P$(b)/$@
binary-all: build install
binary-indep: build install \
ngcp-ngcpcfg \
ngcp-ngcpcfg-locker \
ngcp-ngcpcfg-testsuite
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install

@ -0,0 +1 @@
1.0

@ -0,0 +1,467 @@
ngcpcfg(8)
==========
Name
----
ngcpcfg - central and template based Configuration Management
Synopsis
--------
ngcpcfg <action> [ options ]
Introduction
------------
ngcpcfg is a Configuration Management System, developed for the Sipwise Next
Generation Platform. It provides a central mechanism for handling configuration
changes, updates and synchronisation between servers through a main
configuration which is simple and easy to read and modify.
tl;dr? - ngcpcfg for the impatient
----------------------------------
The main system configuration is done in the file _/etc/ngcp-config/config.yml_.
After modifying the file execute 'ngcpcfg apply' to build the accordingly
configurations file.
Taxonomy
--------
*central yml files*:: *.yml files inside _/etc/ngcp-config/_
*High Availability setup*:: ngcpcfg running in a cluster setup (e.g.
sip:providerPRO or sip:carrier), depends on Debian package ngcp-ngcpcfg-ha.
*local repository*:: the directory _/etc/ngcp-config/_, being a Git repository
*remote systems*:: the other nodes inside a High Availability setup, as defined
in _/etc/ngcp-config/systems.cfg_
*shared repository*:: Git repository shared amongst nodes inside a High
Availability setup, as defined by the GLUSTERFS setting in
/etc/ngcp-config/ngcpcfg.d/shared_storage.cfg (requires ngcp-ngcpcfg-ha) and
being _/mnt/glusterfs_ by default
*templates*:: template toolkit files with .tt2 suffix, found in
_/etc/ngcp-config/templates/etc/_
[[configfiles]]
Configuration files
-------------------
Main configuration files
~~~~~~~~~~~~~~~~~~~~~~~~
* _/etc/ngcp-config/config.yml_: central configuration file, to be configured with
$EDITOR, webfrontend,...
* _/etc/ngcp-config/config.$HOSTNAME.yml_: host specific configuration file,
depending on the hostname (:= $HOSTNAME) of the system.
* _/etc/ngcp-config/config.local.yml_: local configuration, not being host
specific.
* _/etc/ngcp-config/constants.yml_: configuration file that has precedence over
any other .yml file _/etc/ngcp-config/_, defining important constant settings.
This file is *not* supposed to be modified by the user (without having a very
good reason).
* _/etc/ngcp-config/ngcpcfg.cfg_: main configuration file for ngcpcfg itself,
provides global variables used inside ngcpcfg and its helper scripts. This file
is *not* supposed to be modified by the user (without having a very good
reason).
* _/etc/ngcp-config/ngcpcfg.d/_: configuration directory for ngcpcfg itself.
Files with suffix '.cfg' inside this directory are sourced after
/etc/ngcp-config/ngcpcfg.cfg has been read. Files inside this directory are
*not* supposed to be modified by the user (without having a very good reason).
[IMPORTANT]
Configuration file priority: constants.yml takes precedence over
config.local.yml, over config.$HOSTNAME.yml, over config.yml.
High Availability setup specific configuration files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* _/etc/ngcp_ha_node_: defines node name in the High Availability setup, usually
being _sp1_ for the first node and _sp2_ for the second node.
* _/etc/ngcp-config/systems.cfg_: configuration file that specifies to which
hosts changes should be pushed to.
Supported template files
~~~~~~~~~~~~~~~~~~~~~~~~
Example for generating a configuration file named_/etc/foobar/baz_:
* _/etc/ngcp-config/templates/etc/foobar/baz.tt2_: main and default template
file, used by template-handler for generating /etc/foobar/baz. Configuration
file is usually provided by a Debian package.
* _/etc/ngcp-config/templates/etc/foobar/baz.customtt.tt2_: system specific
template file, but configuration usually isn't provided by a Debian package and
can be modified independent from any Debian package mechanism.
* _/etc/ngcp-config/templates/etc/foobar/baz.tt2.$HA_NODE_: node specific
template file. $HA_NODE is determined using the content of /etc/ngcp_ha_node
(usually being _sp1_ for the first node and _sp2_ for the second node on the
Sipwise Next Generation Platform). Wheras _*customtt.tt2_ files are used on all
nodes in a High Availability setup the _*.tt2.$HA_NODE*_ file is specific for
the single node only. A common usage case is master vs. slave configuration of a
service. Configuration file is usually provided by a Debian package. Note:
Feature is available in the High Availability setup only.
* _/etc/ngcp-config/templates/etc/foobar/baz.customtt.tt2.$HA_NODE_: node
specific template file. Regarding $HA_NODE the same as for _baz.tt2.$HA_NODE_
applies (see previous bullet), but the configuration file usually isn't provided
by a Debian package but can be modified independent from any Debian package
mechanism. Note: Feature is available in the High Availability setup only.
[IMPORTANT]
Configuration file priority: *.customtt.tt2.$HA_NODE takes precedence over
*.customtt.tt2, over *.tt2.$HA_NODE, over *.tt2.
Support action related files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Example for handling a configuration file named _/etc/foobar/baz_:
* _/etc/ngcp-config/templates/etc/foobar/baz.services_: service file, defining
actions that have to be executed when file /etc/foobar/baz was modified.
* _/etc/ngcp-config/templates/etc/foobar/ngcpcfg.services_: service file,
defining actions that have to be executed whenever *any* file inside /etc/foobar
was modified.
* _/etc/ngcp-config/templates/etc/foobar/baz.postbuild_: script which is
executed *after* a configuration file (/etc/foobar/baz) has been generated. The
environment variable "$output_file" containing the file name of the generated
configuration file (/etc/foobar/baz) is available within the postbuild script. A
common usage case for postbuild files is adjusting file permissions.
* _/etc/ngcp-config/templates/etc/foobar/baz.prebuild_: script which is
executed *before* a configuration file (/etc/foobar/baz) is generated. The
environment variable "$output_file" containing the file name of the generated
configuration file (/etc/foobar/baz) is available within the postbuild script.
Syntax and layout of configuration files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* _/etc/ngcp-config/ngcpcfg.cfg_: plain shell syntax style "key=value" entries
* _/etc/ngcp-config/systems.cfg_: one hostname or IP address per line
* _central yml files_ (*.yml): YAML configuration syntax (see http://yaml.org/)
* _template files_ (*.tt2): whatever the according software (Kamailio,
MySQL,...) needs. Any variables that should be replaced by the configuration
management system (based on the main configuration files *.yml inside
/etc/ngcp-config/) have to be written in the YAML syntax (see http://yaml.org/)
* _service files_ (*.services) and _build files_ ({post,pre}build): file will be
executed under "bash $FILE", so you can use commands e.g. like
"/etc/init.d/foobar restart" and any further shell scripting syntax inside the
services files
Options
-------
**--debug** <action> [<further_options>]::
Run actions (see next section) in verbose mode, useful for debugging.
**--help**::
Display usage information and exit.
**--version**::
Display ngcpcfg version and exit.
Actions
-------
**apply**::
Executes the _build_, _services_ and _commit_ commands in a batch (assuming each
command worked as expected). This option serves as a shortcut for the most
commonly executed commands.
**build** [--modified-only] [<files_or_directories>|<pattern>]::
Generate configuration files, based on values defined the central yml files and
based on the templates in the configuration tree (/etc/ngcp-config/templates by
default). The *--modified-only* option checks for _modified_ and _uncommitted_
configuration files (central yml files and templates) and builds the relevant
files only. If a central yml file is modified it builds all configuration files.
If changes are in template files only just the according template files are
considered for rebuild. If a file (e.g. _/etc/rsyslog.conf_) or directory (e.g.
_/etc/mysql/_) is provided as argument to the _build_ option only the specified
file / files inside the directory will be generated. If the argument doesn't
start with the /etc prefix the argument is considered as pattern, matching all
files/directories which include the specified pattern. The pattern can include
shell globbing patterns - so argument 'mo..t' will match the files
/etc/ngcp-monitoring-tools/collective-check.conf, /etc/monit/monitrc,
/etc/ha.d/resource.d/monit-services and /etc/default/monit iff they are present.
You can combine _<files_or_directories>_ and _<pattern>_ and use multiple
arguments.
**commit** [<commit_message>]::
Commit all modified files in _/etc/ngcp-config_ and record changes in _/etc_ by
executing the etckeeper(8) command through
'/usr/share/ngcp-ngcpcfg/scripts/etckeeper'. To check whether there are any
pending changes to be committed execute 'ngcpcfg status'.
**decrypt**::
Decrypt /etc/ngcp-config-crypted.tgz.gpg and restore configuration files,
doing the reverse operation of the _encrypt_ option.
Note: This feature is only available if the ngcp-ngcpcfg-locker package is
installed.
**diff** [<options_for_git_diff>]::
Show changes between ngcpcfg's Git repository and the working tree inside
_/etc/ngcp-config_. You can specify options for the underlying 'git diff'
command, e.g. 'ngcpcfg diff HEAD^' will show all changes that have been recorded
with the last _commit_ operation (see manpage git-rev-parse(1) for details how
to specify revisions). If the tool doesn't report anything it means that there
are neither any uncommited changes nor any new or removed files (files which are
not yet (un)registered to the repository).
**encrypt**::
Encrypt /etc/ngcp-config and all resulting configuration files with a user
defined password and save the result as /etc/ngcp-config-crypted.tgz.gpg.
Note: This feature is only available if the ngcp-ngcpcfg-locker package is
installed.
**help**::
Display usage information and exit.
**initialise**::
If ngcpcfg was installed but isn't configured yet the 'initialise' option sets
up ngcpcfg accordingly. Follow the instructions from the <<setup_instructions,
Setup instructions>> section.
**init-mgmt** <server>::
Set up specified '<server>' for usage as shared repository whereas '<server>'
usually corresponds to the IP/hostname of the central management system in a
sip:carrier environment. Further details about the details of the setup
are available in the <<init-mgmt>> section.
Note: This feature is only available if the ngcp-ngcpcfg-carrier package is installed.
**pull**::
Retrieve modifications from shared repository.
Note: This option is available in the High Availability setup only.
**push** [--nobuild] [--noapply] [--shared-only] [<host(s)>]::
Push modifications to shared repository and remote systems. After changes have been
pushed to the node the _apply_ operation will be executed on each remote system
to rebuild the configuration files (unless the '--noapply' operation has been
specified, then only the _build_ operation will be executed). To skip building
any configuration files at all the '--nobuild' option can be specified (implying
to also skip the _apply_ operation). If the '--shared-only' option is set then
the any pending commits will be pushed only to the shared repository only, any
foreign hosts will be skipped then. If hostname(s) or IP address(es) is given
as argument then the changes will be pushed to the shared repository and to the
given hosts only. If no host has has been specified then the hosts specified in
_/etc/ngcp-config/systems.cfg_ are used.
Note: This option is available in the High Availability setup only.
**services** [--dry-run]::
Execute any defined service actions for modified configuration files. If the
_--dry-run_ option is present the services won't be executed but you'll be
noticed which service files would be executed if being invoked without the
_--dry-run__ option.
**status**::
Display the current state of the configuration system, like modified
configuration files and pending actions.
Usage examples
--------------
The main workflow *without* High Availability setup is:
ngcpcfg status # check for pending operations
$EDITOR /etc/ngcp-config/config.yml # adjust/extend configuration
ngcpcfg apply "summary of changes" # build configs, run services + commit changes
If you do not want to execute the _apply_ shortcut command but instead run the
single actions, then you can execute:
ngcpcfg status # check for pending operations
$EDITOR /etc/ngcp-config/config.yml # adjust/extend configuration
ngcpcfg build # generate/update configuration files
ngcpcfg services # restart services for modified configs
ngcpcfg commit "summary of changes" # register changes
The main workflow *with* High Availability setup is:
ngcpcfg status # check for pending operations
ngcpcfg pull # retrieve possibly pending updates
$EDITOR /etc/ngcp-config/config.yml # adjust/extend configuration
ngcpcfg build # generate/update configuration files
ngcpcfg services # restart services for modified configs
ngcpcfg commit "summary of changes" # register changes
ngcpcfg push # upload changes to shared storage + remote systems
ngcpcfg status # check for possibly outstanding issues
[[faq]]
Frequently asked questions
--------------------------
What does ngcpcfg mean?
~~~~~~~~~~~~~~~~~~~~~~~
'ngcp' is the http://www.sipwise.com/[Sipwise Next Generation Communication
Platform] and 'cfg' stands for the ConFiGuration management system of the
ngcp system.
Does ngcpcfg require a shared storage?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Only if you are using ngcpcfg in a High Availability setup and using the 'push'
functionality (which is highly recommended in a HA Setup).
How does the configuration management system work?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ngcpcfg takes the central yml files (/etc/ngcp-config/*.yml) as input for
configuration, searches for supported templates files (*.tt2) in the template
pool (_/etc/ngcp-config/templates/etc/_) and builds the resulting configuration
files in _/etc_.
[[errorhandling]]
Error handling - what does this error message mean?
---------------------------------------------------
Error message:
Error: Failed hosts: hostname (down)
Background: The system "hostname" is not reachable via ICMP, which means it's
not reachable for the ngcpcfg system.
How to fix: Make sure the system is up and running and reachable via ssh from
the system where you are running the "pull" action.
Error message:
error: Your local changes to 'config.yml' would be overwritten by merge. Aborting.
Background: the file 'config.yml' (in this example) on the system where you are
pushing to contains local modifications which are uncommitted yet. To avoid data
damage the system can't resolve this situation automatically.
How to fix:
1) Throw away the changes on the remote system (where you are pushing to,
important: your changes on the system where you are executing the commands will
be gone!):
cd /etc/ngcp-config ; git checkout -- config.yml
To get rid of *any* modified files (included added/removed files) the following
commands will do the job (use with care and only execute it if you're aware of
the consequences):
cd /etc/ngcp-config
git checkout -- .
git clean -xdf
2) Resolve the merge conflict:
cd /etc/ngcp-config
git pull
$EDITOR config.yml # resolve conflict
ngcpcfg commit 'merge conflict on system sp2'
ngcpcfg pull # just to make sure
ngcpcfg push # push changes back to the other systems
[[init-mgmt]]
init-mgmt setup
---------------
This section documents the 'ngcpcfg init-mgmt' feature in more detail.
The feature is provided through the ngcp-ngcpcfg-carrier package.
The script deprecates the shared repository /mnt/glusterfs/ngcpcfg-share of the
local system by renaming it to /mnt/glusterfs/ngcpcfg-share.unused. It then
registers the two according nodes (the local system plus the second node which
makes the PRO pair) in /etc/ngcp-config/systems.cfg. It sets the 'mgmgt_server'
variable in /etc/ngcp-config/carrier.cfg to '<server>'. Then it makes sure that
the automated login via SSH between the two according nodes as well as the
<server> works. It clones the local shared repository to the '<server>'. Finally
it updates the remote origin for the shared repository on both nodes to point to
'<server>:/mnt/glusterfs/ngcpcfg_<role>' whereas '<role>' corresponds to the
system's hostname without the trailing 'a' and 'b' suffix.
[NOTE]
To check which remote repository is in use execute
'cd /etc/ngcp-config; git remote show origin | grep URL'.
[[setup_instructions]]
Setup instructions
------------------
Requirements for High Availability setup:
* glusterfs is supposed to be set up working and deployed at /mnt/glusterfs
(as defined via /etc/ngcp-config/ngcpcfg.cfg)
* hosts are expected to be set up for automatic ssh login (ssh-keygen && ssh-copy-id)
* node names are expected to be sp1 and sp2 so the .tt2.sp1 and .tt2.sp2
template files are supported
Configuration on sp1 (expected to be master node in initial setup):
ngcpcfg initialise
ngcpcfg build
printf "sp1\nsp2\n" > /etc/ngcp-config/systems.cfg
ngcpcfg commit "provide systems.cfg"
Configuration on sp2 (and any further existing system):
ngcpcfg initialise
ngcpcfg build
Please note that you do not have to run this steps if you are using the Sipwise
Next Generation Platform since the installation steps are fully automated.
Involved frameworks
-------------------
* git: Distributed Version Control system
* tt2: Template Toolkit
* make: Utility for Directing compilation
* yaml: Generic data serialization language
Limitations
-----------
ngcpcfg was designed specifically for the Sipwise Next Generation Platform,
though with being as generic as possible in mind. The system is supposed to be
useful for configuration management on other systems/platforms and it's possible
to adapt it for different needs through a variety of configuration parameters,
though keep in mind that ngcpcfg was implemented for some very specific use
cases.
Author
------
Michael Prokop <mprokop@sipwise.com>
/////////////////////////////
// vim: ft=asciidoc tw=80 ai
/////////////////////////////

@ -0,0 +1,22 @@
# Filename: /etc/ngcp-config/ngcpcfg.cfg
# Purpose: main configuration file for ngcpcfg tools
# Note: do not modify unless you have a really good reason to do so
# directory name where ngcpcfg is managed through git
NGCPCTL_MAIN='/etc/ngcp-config'
NGCPCTL_CONFIG="${NGCPCTL_MAIN}/config.yml"
HOST_CONFIG="${NGCPCTL_MAIN}/config.$(hostname).yml"
LOCAL_CONFIG="${NGCPCTL_MAIN}/config.local.yml"
CONSTANTS_CONFIG="${NGCPCTL_MAIN}/constants.yml"
NETWORK_CONFIG="${NGCPCTL_MAIN}/network.yml"
# configuration files that should be managed
CONFIG_POOL='/etc'
# location of templates
TEMPLATE_POOL="${NGCPCTL_MAIN}/templates/${CONFIG_POOL}"
# location of service definitions
SERVICES_POOL="${NGCPCTL_MAIN}/templates/${CONFIG_POOL}"
## END OF FILE #################################################################

@ -0,0 +1,192 @@
# Filename: /usr/share/ngcp-ngcpcfg/functions/main
# Purpose: helper functions for ngcpcfg
################################################################################
## logging functions {{{
log_info() {
logger -t ngcpcfg -- "$*"
echo "$*"
}
# info without ending newline
log_info_n() {
logger -t ngcpcfg -- "$*"
printf -- "$*"
}
log_warn() {
logger -t ngcpcfg -- "Warning: $*"
echo "Warning: $*"
}
log_error() {
logger -t ngcpcfg -- "Error: $*"
echo "Error: $*" >&2
}
log_debug() {
if [ -n "${DEBUG:-}" ] ; then
logger -t ngcpcfg -- "Debug: $*"
echo ; echo "DEBUG: $*" ; echo # newlines to avoid messup with cmdline output
fi
}
## }}}
## important variables we depend on to operate successfully {{{
# support test suite which requires system independent configuration
if [ -r ngcpcfg-testsuite.cfg ] ; then
. ngcpcfg-testsuite.cfg
else
if [ -r /etc/ngcp-config/ngcpcfg.cfg ] ; then
log_debug "sourcing configuration file /etc/ngcp-config/ngcpcfg.cfg"
. /etc/ngcp-config/ngcpcfg.cfg
if [ -d /etc/ngcp-config/ngcpcfg.d ] ; then
for file in /etc/ngcp-config/ngcpcfg.d/*.cfg ; do
if test -r $file ; then
log_debug "sourcing configuration file $file"
. $file
fi
done
fi
elif [ -r /etc/ngcp-config-crypted.tgz.gpg ] ; then
log_error "Configuration pool locked. Please contact your distributor. Exiting."
exit 1
else
log_error "Could not read configuration file /etc/ngcp-config/ngcpcfg.cfg. Exiting."
exit 1
fi
fi
if ! [ -r "$NGCPCTL_CONFIG" ] ; then
log_error "Configuration file ${NGCPCTL_CONFIG} does not exist (unconfigured?) - exiting."
exit 1
fi
if ! [ -r "$CONSTANTS_CONFIG" ] ; then
log_error "Constants file ${CONSTANTS_CONFIG} does not exist (unconfigured?) - exiting."
exit 1
fi
if ! [ -n "${NETWORK_CONFIG:-}" ] ; then
log_warn "NETWORK_CONFIG is not configured in $NGCPCTL_CONFIG - continuing anyway."
elif ! [ -r "$NETWORK_CONFIG" ] ; then
log_error "Constants file ${NETWORK_CONFIG} does not exist (unconfigured?) - exiting."
exit 1
fi
if ! [ -d "$TEMPLATE_POOL" ] ; then
log_error "No template directory (${TEMPLATE_POOL}) found - exiting."
exit 1
fi
## }}}
## environment variables {{{
export PN="ngcpcfg"
export HNAME="$(hostname)"
# avoid warnings by perl script complaining about locales
export LANG=C
export LC_ALL=C
# make sure it's available in all helper scripts
[ -n "${DEBUG:-}" ] && export DEBUG
# export for access via build_config etc
export CONFIG_POOL
export HOST_CONFIG
export LOCAL_CONFIG
export NGCPCTL_CONFIG
export CONSTANTS_CONFIG
export NETWORK_CONFIG
## }}}
## HA / carrier features {{{
if [ -r /usr/share/ngcp-ngcpcfg/functions/ha_features ] ; then
. /usr/share/ngcp-ngcpcfg/functions/ha_features
set_ha_file # set $HA_FILE for usage in generate_template_list
fi
if [ -r /usr/share/ngcp-ngcpcfg/functions/carrier_features ] ; then
. /usr/share/ngcp-ngcpcfg/functions/carrier_features
fi
## }}}
## functions {{{
generate_template_list() {
[ -n "$TEMPLATE_POOL" ] || return 1
local filelist_prepared=$(mktemp)
local filelist_final=$(mktemp)
# iterate over all files
for file in $(find "$TEMPLATE_POOL" -name \*.tt2 -o -name \*.tt2"${HA_FILE:-}") ; do
# *NO* arguments provided via cmdline
if [ -z "${1:-}" ] ; then
echo "$file" >> "${filelist_prepared}"
else
# arguments (file list/pattern) provided via cmdline
for arg in $* ; do
if echo $file | grep -q "${arg}" ; then
echo "$file" >> "${filelist_prepared}"
fi
done
fi
done
# remove all filenames where a preferred filename exists
# foo.customtt.tt2.spX > foo.customtt.tt2 > foo.tt2.spX > foo.tt2
for line in $(cat ${filelist_prepared}); do
# reduce filenames from "foo.*" to "foo"
if [ -n "${HA_FILE:-}" ] ; then
normalized_filename="${line%${HA_FILE}}"
else
normalized_filename="${line}"
fi
normalized_filename="${normalized_filename%.customtt.tt2}"
normalized_filename="${normalized_filename%.tt2}"
# foo.customtt.tt2.sp{1,2}
if [ -n "${HA_FILE:-}" ] ; then
if grep -q "^${normalized_filename}.customtt.tt2${HA_FILE:-}" "${filelist_prepared}" ; then
echo "${normalized_filename}.customtt.tt2${HA_FILE:-}" >> "${filelist_final}"
continue
fi
fi
# foo.customtt.tt2
if grep -q "^${normalized_filename}.customtt.tt2$" "${filelist_prepared}" ; then
echo "${normalized_filename}.customtt.tt2" >> "${filelist_final}"
continue
fi
# foo.tt2.sp{1,2}
if [ -n "${HA_FILE:-}" ] ; then
if grep -q "^${normalized_filename}.tt2${HA_FILE}" "${filelist_prepared}" ; then
echo "${normalized_filename}.tt2${HA_FILE}" >> "${filelist_final}"
continue
fi
fi
# file should be used, so list it
echo "$line" >> "${filelist_final}"
done
# output file list, make sure we provide the file names just once
sort -u ${filelist_final}
if [ -n "${DEBUG:-}" ] ; then
# send to stderr since stdout is used from outside
log_debug "Not removing temporary filelist files since we are in debug mode:" >&2
log_debug " filelist_prepared = ${filelist_prepared}" >&2
log_debug " filelist_final = ${filelist_final}" >&2
else
rm -f "${filelist_prepared}" "${filelist_final}"
fi
unset filelist_prepared filelist_final
}
## }}}
## END OF FILE #################################################################

@ -0,0 +1,102 @@
#!/bin/bash
# Filename: /usr/share/ngcp-ngcpcfg/helper/build_config
# Purpose: builds output configuration file based on tt2 template file
# using /usr/share/ngcp-ngcpcfg/helper/tt2-wrapper
################################################################################
set -e
set -u
if [ "${#:-}" -ne 1 ] ; then
echo "Usage: /usr/share/ngcp-ngcpcfg/helper/build_config <input_file>" >&2
exit 1
fi
if [ -z "${CONFIG_POOL:-}" ] ; then
echo "Error: $CONFIG_POOL is not set." >&2
exit 1
fi
# support for testsuite
if [ -z "${FUNCTIONS:-}" ] ; then
FUNCTIONS='/usr/share/ngcp-ngcpcfg/functions/'
fi
if [ -z "${HELPER:-}" ] ; then
HELPER='/usr/share/ngcp-ngcpcfg/helper/'
fi
. ${FUNCTIONS}/main
# main script
input_file="$1" # like /etc/ngcp-config/templates/etc/mysql/my.cnf.tt2
# calculate output file {{{
x=${input_file##${NGCPCTL_MAIN}/templates/} # drop leading /etc/ngcp-config
y=${x%%.tt2} # drop trailing suffix '.tt2'
[ -n "${HA_FILE:-}" ] && y=${y%%.tt2${HA_FILE}} # drop trailing suffix '.tt2.sp{1,2}'
y=${y%%.customtt} # drop trailing suffix '.customtt'
# }}}
export output_file="${y}" # like /etc/mysql/my.cnf, export variable
# for usage within {pre,post}build scripts
# pre-execution script in template store:
if [ -r "${NGCPCTL_MAIN}/templates/${output_file}.prebuild" ] ; then
log_info "Executing prebuild for ${output_file}"
bash "${NGCPCTL_MAIN}/templates/${output_file}.prebuild"
elif [ -r "${NGCPCTL_MAIN}/templates/$(dirname ${output_file})/ngcpcfg.prebuild" ] ; then
log_info "Executing prebuild for ${output_file}"
bash "${NGCPCTL_MAIN}/templates/$(dirname ${output_file})/ngcpcfg.prebuild"
fi
# if output directory does not exist yet, create it
if ! [ -d "$(dirname ${output_file})" ] ; then
umask 0022 # directory permissions should be '755'
mkdir -p "$(dirname ${output_file})"
fi
# assume safe defaults
umask 0077
# read host specific configuration file only if it exists
[ -r "${HOST_CONFIG:-}" ] && host_conf="$HOST_CONFIG"
# read local config only if it exists
[ -r "${LOCAL_CONFIG:-}" ] && local_conf="$LOCAL_CONFIG"
TT_WRAPPER="${HELPER}/tt2-wrapper"
log_debug "Output file ${output_file} based on ${input_file}"
log_debug "Executing: $TT_WRAPPER ${input_file} ${host_conf:-} ${local_conf:-} $NGCPCTL_CONFIG ${NETWORK_CONFIG:-} $CONSTANTS_CONFIG > ${output_file}"
if "$TT_WRAPPER" "${input_file}" ${host_conf:-} ${local_conf:-} "$NGCPCTL_CONFIG" "${NETWORK_CONFIG:-}" "$CONSTANTS_CONFIG" > "${output_file}" 2>/dev/null ; then
log_info "Generating ${output_file}: OK"
RC=0
else
log_error "Generating ${output_file} based on ${input_file}: FAILED"
RC=1
log_info "NOTE: Check those files for valid syntax and encoding:"
for f in "${input_file}" ${host_conf:-} ${local_conf:-} "$NGCPCTL_CONFIG" "${NETWORK_CONFIG:-}" "$CONSTANTS_CONFIG" ; do
[ -r "$f" ] && log_info "$f"
done
log_info "Running /usr/share/ngcp-ngcpcfg/helper/tt2-wrapper <file> should provide more details."
fi
# set permissions for generated config based on the ones of the template
chmod --reference="${input_file}" "${output_file}"
# finally drop all write permissions
chmod a-w "${output_file}"
# post-execution script in template store:
if [ -r "${NGCPCTL_MAIN}/templates/${output_file}.postbuild" ] ; then
log_info "Executing postbuild for ${output_file}"
bash "${NGCPCTL_MAIN}/templates/${output_file}.postbuild"
elif [ -r "${NGCPCTL_MAIN}/templates/$(dirname ${output_file})/ngcpcfg.postbuild" ] ; then
log_info "Executing postbuild for ${output_file}"
bash "${NGCPCTL_MAIN}/templates/$(dirname ${output_file})/ngcpcfg.postbuild"
fi
exit $RC
## END OF FILE #################################################################

@ -0,0 +1,21 @@
#!/usr/bin/perl
# Purpose: report internal->fileformat setting of /etc/ngcp-config/config.yml
################################################################################
use strict;
use warnings;
use YAML::Tiny;
my $yaml = YAML::Tiny->new;
$yaml = YAML::Tiny->read("/etc/ngcp-config/config.yml");
my $fileformat = $yaml->[0]->{internal}->{fileformat};
if (defined $fileformat) {
print "$fileformat\n";
exit 0;
} else {
print "undefined\n";
exit 1;
}
## END OF FILE #################################################################

@ -0,0 +1,18 @@
#!/usr/bin/perl -CSD
# Purpose: sort yaml configuration file
################################################################################
use strict;
use warnings;
use YAML::Tiny;
my $yaml = YAML::Tiny->new;
my $inputfile = shift or die 'You did not specify an input file name';
my $outputfile = shift or die 'You did not specify an ouput file name';
$yaml = YAML::Tiny->read($inputfile);
open(my $fh, '>', "$outputfile") or die "Could not open $outputfile for writing";
print $fh $yaml->write_string() or die "Could not write YAML to $outputfile";
## END OF FILE #################################################################

@ -0,0 +1,188 @@
#!/usr/bin/perl -CSD
# Purpose: template toolkit helper script
################################################################################
use strict;
use warnings;
use YAML qw/LoadFile/;
use Template;
use Hash::Merge qw(merge);
use DBI;
sub sync_extra_sockets;
my $tt = Template->new({ ABSOLUTE => 1, RELATIVE => 1 });
my $config = {};
foreach my $file (@ARGV) {
$config = merge($config, LoadFile($file) || die $!);
}
open my $SWFH, '<', '/etc/mysql/sipwise.cnf';
my $dbpass = join ' ', <$SWFH>;
close $SWFH;
$dbpass =~ s/^.*SIPWISE_DB_PASSWORD=\'([^\']+)\'.*$/$1/;
chomp $dbpass;
my $dbuser = 'sipwise';
my $dbname = $config->{ossbss}->{provisioning}->{database}->{name};
unless(defined $dbname) {
print "Could not determine provisioning db name\n";
exit 1;
}
unless(defined $dbuser) {
print "Could not determine provisioning db user\n";
exit 1;
}
unless(defined $dbpass) {
print "Could not determine provisioning db password\n";
exit 1;
}
my $dbh = DBI->connect('DBI:mysql:'.$dbname, $dbuser, $dbpass);
unless(defined $dbh) {
print "Could not connect to database '$dbname': $DBI::errstr\n";
exit 1;
}
exit 1 unless(sync_extra_sockets());
$dbh->disconnect;
# this part sync with kamailio db
$dbuser = $config->{kamailio}->{proxy}->{dbrwuser};
$dbname = $config->{kamailio}->{proxy}->{dbname};
$dbpass = $config->{kamailio}->{proxy}->{dbrwpw};
unless(defined $dbname) {
print "Could not determine kamailio db name\n";
exit 1;
}
unless(defined $dbuser) {
print "Could not determine kamailio db user\n";
exit 1;
}
unless(defined $dbpass) {
print "Could not determine kamailio db password\n";
exit 1;
}
$dbh = DBI->connect('DBI:mysql:'.$dbname, $dbuser, $dbpass);
unless(defined $dbh) {
print "Could not connect to database '$dbname': $DBI::errstr\n";
exit 1;
}
exit 1 unless(sync_faxserver_uris());
$dbh->disconnect;
exit 0;
## kamailio.lb.extra_sockets handling: ##############################
sub sync_extra_sockets {
my $pref_name = 'outbound_socket';
my $sth = $dbh->prepare("select id from voip_preferences where attribute=?");
$sth->execute($pref_name);
my $res = $sth->fetchrow_hashref();
unless(defined $res) {
print "Could not find preference '$pref_name' in db\n";
return;
}
my $pref_id = $res->{id};
$sth->finish;
my $enum_insert_sth = $dbh->prepare("insert into voip_preferences_enum (preference_id, label, value, usr_pref, dom_pref, peer_pref) values(?, ?, ?, 1, 1, 1)");
my $enum_update_sth = $dbh->prepare("update voip_preferences_enum set value=? where id=?");
my $enum_delete_sth = $dbh->prepare("delete from voip_preferences_enum where id=?");
$sth = $dbh->prepare("select id, label, value from voip_preferences_enum where preference_id=?");
$sth->execute($pref_id);
my $sockets = $config->{kamailio}->{lb}->{extra_sockets};
my $dbsockets = $sth->fetchall_hashref('label');
$sth->finish;
foreach my $row (keys %{$dbsockets}) {
$row = $dbsockets->{$row};
next if($row->{label} eq 'default');
if(!exists $sockets->{$row->{label}}) {
print "socket $row->{label} does not exist anymore in config, delete from db\n";
$enum_delete_sth->execute($row->{id});
} elsif($sockets->{$row->{label}} ne $row->{value}) {
print "update $row->{label}=$row->{value} to $row->{label}=$sockets->{$row->{label}} in db\n";
$enum_update_sth->execute($sockets->{$row->{label}}, $row->{id});
delete $sockets->{$row->{label}};
} else {
print "socket $row->{label}=$row->{value} is sync between config and db\n";
delete $sockets->{$row->{label}};
}
}
foreach my $sock(keys %{$sockets}) {
print "insert new socket $sock=$sockets->{$sock} from config into db\n";
$enum_insert_sth->execute($pref_id, $sock, $sockets->{$sock});
}
$enum_insert_sth->finish;
$enum_update_sth->finish;
$enum_delete_sth->finish;
return 1;
}
## faxserver.hw_fax_gateways handling: ##############################
sub sync_faxserver_uris {
my $fax_set_id = 4;
my $reload_dispatcher = 0;
my $dispatcher_insert_sth = $dbh->prepare("insert into dispatcher (setid, destination, flags, priority, description) values(4, ?, 0, 0, 'Fax2Mail Servers')");
my $dispatcher_delete_sth = $dbh->prepare("delete from dispatcher where id=?");
my $sth = $dbh->prepare("select id,destination from dispatcher where setid=?");
$sth->execute($fax_set_id);
my $db_fax_gateways = $sth->fetchall_hashref('destination');
$sth->finish;
# array reference
my $yaml_fax_gateways = $config->{faxserver}->{fax_gateways};
unless(defined $yaml_fax_gateways) {
return 1;
}
my @tmp_array = @{$yaml_fax_gateways};
# turn the array into hash reference
my $fax_gateways = {};
foreach my $gw (@tmp_array) {
# e.g: sip:127.0.0.1:5070/255.255.255.0, remove /255.255.255.0
my @new_gw_parts = split('/', $gw);
my $gw_sip_parts = $new_gw_parts[0];
$fax_gateways->{$gw_sip_parts} = 1 ;
}
foreach my $row (keys %{$db_fax_gateways}) {
$row = $db_fax_gateways->{$row};
if(!exists $fax_gateways->{$row->{destination}}) {
print "fax gateway $row->{destination} does not exist anymore in config, delete from db\n";
$dispatcher_delete_sth->execute($row->{id});
$reload_dispatcher ||= 1;
} else {
print "fax gateway $row->{destination} sync between config and db\n";
delete $fax_gateways->{$row->{destination}};
}
}
foreach my $fax_gw(keys %{$fax_gateways}) {
print "insert new fax gateway $fax_gw from config into db\n";
$dispatcher_insert_sth->execute($fax_gw);
$reload_dispatcher ||= 1;
}
$dispatcher_insert_sth->finish;
$dispatcher_delete_sth->finish;
if($reload_dispatcher){
print "fax gateway changes, need to reload kamailio dispatcher ... \n";
my $result = `ngcp-kamctl proxy dispatcher reload`;
print "reload kamailio dispatcher done, status was: $? \n";
}
return 1;
}
## END OF FILE #################################################################

@ -0,0 +1,26 @@
#!/usr/bin/perl -CSD
# Purpose: template toolkit helper script
################################################################################
use strict;
use warnings;
use YAML qw/LoadFile/;
use Template;
use Hash::Merge qw(merge);
my $tt = Template->new({ ABSOLUTE => 1, RELATIVE => 1, EVAL_PERL => 1 });
my $template = shift(@ARGV);
my $config = {};
foreach my $file (@ARGV) {
$config = merge($config, LoadFile($file) || die $!);
}
# NOTE: we can't rely on "$tt->process($template, $config)" because the config
# file is UTF8 encoded but is then being read as a binary 8bit file and written
# as UTF8 file again, causing wide characters getting encoded twice
open my $fh, '<', $template or die "Unable to open file for reading: $!";
$tt->process($fh, $config) or die $tt->error;
## END OF FILE #################################################################

@ -0,0 +1,17 @@
#!/usr/bin/perl -CSD
# Purpose: validate yml file format
################################################################################
use strict;
use warnings;
use YAML::Tiny;
use File::Temp qw/tempfile/;
my $yaml = YAML::Tiny->new;
my $inputfile = shift or die 'You did not specify an input file name';
my $outputfile = new File::Temp( UNLINK => 1 );
$yaml = YAML::Tiny->read($inputfile);
open(my $fh, '>', "$outputfile") or die "Could not open $outputfile for writing";
print $fh $yaml->write_string() or die "Could not write YAML to $outputfile";
## END OF FILE #################################################################

@ -0,0 +1,30 @@
[%
# Return an array of advertised IPs from the interface of a given
# type for all nodes which act as a given role
#
# @param argv.role The role of the node to process
# One of: proxy, lb, mgmt
# @param argv.type The interface type of a node to extract
# the advertised ips from
# One of: web_int, web_ext, sip_int, sip_ext, ...
# @return out The array of advertised ips
-%]
[% blktmp.processed_hosts = {} -%]
[% out = [] -%]
[% FOREACH host IN hosts.keys -%]
[% IF hosts.$host.role.grep('^' _ argv.role _ '$').size() && !blktmp.processed_hosts.$host.defined -%]
[% FOREACH iface IN hosts.$host.interfaces -%]
[% FOREACH realiface IN hosts.$host.keys -%]
[% IF realiface == iface -%]
[% IF hosts.$host.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% peer = hosts.$host.peer -%]
[% blktmp.processed_hosts.$peer = 1 -%]
[% FOREACH ip IN hosts.$host.$realiface.advertised_ip -%]
[% out.push(ip) -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,21 @@
[%
# Return an array of advertised IPs for a given host
#
# @param argv.host The host to get all shared IPs for.
# @param argv.type The interface type or empty string for all types.
# @return out The array of advertised ips.
-%]
[% IF !hosts.${argv.host}.defined -%][% argv.host = 'self' -%][% END -%]
[% out = [] -%]
[% IF !argv.type.length -%][% argv.type = '.*' -%][% END -%]
[% FOREACH iface IN hosts.${argv.host}.interfaces -%]
[% FOREACH realiface IN hosts.${argv.host}.keys -%]
[% IF realiface == iface -%]
[% IF hosts.${argv.host}.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% FOREACH ip IN hosts.${argv.host}.$realiface.advertised_ip -%]
[% out.push(ip) -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,31 @@
[%
# Return an array of hashes with name and ip within a given type
# for all nodes.
#
# @param argv.role The role of the node to process
# One of: proxy, lb, mgmt
# @param argv.type The interface type of a node to extract
# the ip from
# One of: web_int, web_ext, sip_int, sip_ext, ...
# @return out The array of hashes with fields "name" and "ip", e.g.:
# [
# {name=>'sp1', ip='192.168.255.251'},
# {name=>'sp2', ip='192.168.255.252'}
# ]
-%]
[% out = [] -%]
[% FOREACH host IN hosts.keys -%]
[% IF hosts.$host.role.grep('^' _ argv.role _ '$').size() -%]
[% FOREACH iface IN hosts.$host.interfaces -%]
[% FOREACH realiface IN hosts.$host.keys -%]
[% IF realiface == iface -%]
[% IF hosts.$host.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% IF !out.grep('^' _ hosts.$host.$realiface.ip _ '$').size() -%]
[% out.push({ name = host, ip = hosts.$host.$realiface.ip }) -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,27 @@
[%
# Return an array of IPs from the interface of a given
# type for all nodes which act as a given role
#
# @param argv.role The role of the node to process
# One of: proxy, lb, mgmt
# @param argv.type The interface type of a node to extract
# the ip from
# One of: web_int, web_ext, sip_int, sip_ext, ...
# @return out The array of ips
-%]
[% out = [] -%]
[% FOREACH host IN hosts.keys -%]
[% IF hosts.$host.role.grep('^' _ argv.role _ '$').size() -%]
[% FOREACH iface IN hosts.$host.interfaces -%]
[% FOREACH realiface IN hosts.$host.keys -%]
[% IF realiface == iface -%]
[% IF hosts.$host.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% IF !out.grep('^' _ hosts.$host.$realiface.ip _ '$').size() -%]
[% out.push(hosts.$host.$realiface.ip) -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,19 @@
[%
# Return an array of IPs for a given host.
#
# @param argv.host The host to get all IPs for.
# @param argv.type The interface type or empty string for all types.
# @return out The array of ips.
-%]
[% IF !hosts.${argv.host}.defined -%][% argv.host = 'self' -%][% END -%]
[% out = [] -%]
[% IF !argv.type.length -%][% argv.type = '.*' -%][% END -%]
[% FOREACH iface IN hosts.${argv.host}.interfaces -%]
[% FOREACH realiface IN hosts.${argv.host}.keys -%]
[% IF realiface == iface -%]
[% IF hosts.${argv.host}.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% out.push(hosts.${argv.host}.$realiface.ip) -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,30 @@
[%
# Return an array of shared IPs from the interface of a given
# type for all nodes which act as a given role
#
# @param argv.role The role of the node to process
# One of: proxy, lb, mgmt
# @param argv.type The interface type of a node to extract
# the shared ip from
# One of: web_int, web_ext, sip_int, sip_ext, ...
# @return out The array of shared ips
-%]
[% blktmp.processed_hosts = {} -%]
[% out = [] -%]
[% FOREACH host IN hosts.keys -%]
[% IF hosts.$host.role.grep('^' _ argv.role _ '$').size() && !blktmp.processed_hosts.$host.defined -%]
[% FOREACH iface IN hosts.$host.interfaces -%]
[% FOREACH realiface IN hosts.$host.keys -%]
[% IF realiface == iface -%]
[% IF hosts.$host.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% peer = hosts.$host.peer -%]
[% blktmp.processed_hosts.$peer = 1 -%]
[% FOREACH ip IN hosts.$host.$realiface.shared_ip -%]
[% out.push(ip) -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,21 @@
[%
# Return an array of shared IPs for a given host
#
# @param argv.host The host to get all shared IPs for.
# @param argv.type The interface type or empty string for all types.
# @return out The array of shared ips.
-%]
[% IF !hosts.${argv.host}.defined -%][% argv.host = 'self' -%][% END -%]
[% out = [] -%]
[% IF !argv.type.length -%][% argv.type = '.*' -%][% END -%]
[% FOREACH iface IN hosts.${argv.host}.interfaces -%]
[% FOREACH realiface IN hosts.${argv.host}.keys -%]
[% IF realiface == iface -%]
[% IF hosts.${argv.host}.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% FOREACH ip IN hosts.${argv.host}.$realiface.shared_ip -%]
[% out.push(ip) -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,30 @@
[%
# Return an array of shared IPv6 addresses from the interface of a given
# type for all nodes which act as a given role
#
# @param argv.role The role of the node to process
# One of: proxy, lb, mgmt
# @param argv.type The interface type of a node to extract
# the shared ip from
# One of: web_int, web_ext, sip_int, sip_ext, ...
# @return out The array of shared IPv6 addresses
-%]
[% blktmp.processed_hosts = {} -%]
[% out = [] -%]
[% FOREACH host IN hosts.keys -%]
[% IF hosts.$host.role.grep('^' _ argv.role _ '$').size() && !blktmp.processed_hosts.$host.defined -%]
[% FOREACH iface IN hosts.$host.interfaces -%]
[% FOREACH realiface IN hosts.$host.keys -%]
[% IF realiface == iface -%]
[% IF hosts.$host.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% peer = hosts.$host.peer -%]
[% blktmp.processed_hosts.$peer = 1 -%]
[% FOREACH ip IN hosts.$host.$realiface.shared_v6ip -%]
[% out.push(ip) -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,21 @@
[%
# Return an array of shared IPs for a given host
#
# @param argv.host The host to get all shared IPs for.
# @param argv.type The interface type or empty string for all types.
# @return out The array of shared ips
-%]
[% IF !hosts.${argv.host}.defined -%][% argv.host = 'self' -%][% END -%]
[% out = [] -%]
[% IF !argv.type.length -%][% argv.type = '.*' -%][% END -%]
[% FOREACH iface IN hosts.${argv.host}.interfaces -%]
[% FOREACH realiface IN hosts.${argv.host}.keys -%]
[% IF realiface == iface -%]
[% IF hosts.${argv.host}.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% FOREACH ip IN hosts.${argv.host}.$realiface.shared_v6ip -%]
[% out.push(ip) -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,25 @@
[%
# Return an array of IPv6 addresses from the interface of a given
# type for all nodes which act as a given role
#
# @param argv.role The role of the node to process
# One of: proxy, lb, mgmt
# @param argv.type The interface type of a node to extract
# the ip from
# One of: web_int, web_ext, sip_int, sip_ext, ...
# @return out The array of ips
-%]
[% out = [] -%]
[% FOREACH host IN hosts.keys -%]
[% IF hosts.$host.role.grep('^' _ argv.role _ '$').size() -%]
[% FOREACH iface IN hosts.$host.interfaces -%]
[% FOREACH realiface IN hosts.$host.keys -%]
[% IF realiface == iface -%]
[% IF hosts.$host.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% out.push(hosts.$host.$realiface.v6ip) -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,22 @@
[%
# Return an array of IPs for a given host. The order is iface1_sharedip_1,
# iface1_sharedip_n, iface1_ip, iface2_sharedip_1, ...
#
# @param argv.host The host to get all IPs for.
# @param argv.type The interface type or empty string for all types.
# @return out The array of ips.
-%]
[% IF !hosts.${argv.host}.defined -%][% argv.host = 'self' -%][% END -%]
[% out = [] -%]
[% IF !argv.type.length -%][% argv.type = '.*' -%][% END -%]
[% FOREACH iface IN hosts.${argv.host}.interfaces -%]
[% FOREACH realiface IN hosts.${argv.host}.keys -%]
[% IF realiface == iface -%]
[% IF hosts.${argv.host}.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% IF hosts.${argv.host}.$realiface.v6ip.defined -%]
[% out.push(hosts.${argv.host}.$realiface.v6ip) -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,15 @@
[%
# Returns the (alphabetically) first hostname of a node pair for
# a given host.
#
# @param argv.host The hostname to get the first name for.
# @return out The alphabetically first name.
-%]
[% IF !hosts.${argv.host}.defined -%]
[% argv.host = 'self' -%]
[% END -%]
[% blktmp.hosts = [argv.host] -%]
[% IF hosts.${argv.host}.peer.defined -%]
[% blktmp.hosts.push(hosts.${argv.host}.peer) -%]
[% END -%]
[% out = blktmp.hosts.sort.0 -%]

@ -0,0 +1,15 @@
[%
# Returns the hostname of the node calling this function.
#
# @return out The hostname of the node calling this function.
-%]
[% PERL -%]
# don't trust hostname(1) as this might differ from the hostname of
# the system which runs the installer, instead rely on /etc/hostname
open my $hh, '<', '/etc/hostname' or die "Error opening /etc/hostname";
my $hostname = <$hh>;
close $hh;
chomp $hostname;
die "Fatal error retrieving hostname [$hostname]" unless length $hostname;
$stash->set(out => $hostname);
[% END -%]

@ -0,0 +1,23 @@
[%
# Returns the interface name with a certain type for a given host
#
# @param argv.host The hostname to get the interface from.
# @param argv.type The interface type
# One of: web_int, web_ext, sip_int, sip_ext, ...
# @return out The interface name
-%]
[% IF !hosts.${argv.host}.defined -%]
[% argv.host = 'self' -%]
[% END -%]
[% out = '' -%]
[% FOREACH iface IN hosts.${argv.host}.interfaces -%]
[% FOREACH realiface IN hosts.${argv.host}.keys -%]
[% IF realiface == iface -%]
[% IF hosts.${argv.host}.$realiface.type.grep('^' _ argv.type _ '$').size() -%]
[% out = realiface -%]
[% RETURN -%]
[% END -%]
[% END -%]
[% END -%]
[% END -%]

@ -0,0 +1,10 @@
[%
# Returns the peer name of a given host
#
# @param argv.host The hostname to get the peername for.
# @return out The peername.
-%]
[% IF !hosts.${argv.host}.defined -%]
[% argv.host = 'self' -%]
[% END -%]
[% out = hosts.${argv.host}.peer -%]

@ -0,0 +1,15 @@
[%
# Checks whether a given host has a given role
#
# @param argv.host The hostname to check the role for
# @param argv.role The role of the node to process
# One of: proxy, lb, mgmt
# @return out 0 if false, 1 if true
-%]
[% IF !hosts.${argv.host}.defined -%]
[% argv.host = 'self' -%]
[% END -%]
[% out = 0 -%]
[% IF hosts.${argv.host}.role.grep('^' _ argv.role _ '$').size() -%]
[% out = 1 -%]
[% END -%]

@ -0,0 +1,781 @@
#!/usr/bin/perl -CSD
use warnings;
use strict;
use Carp;
use Data::Validate::IP;
use English qw( -no_match_vars );
use Getopt::Long;
use IO::Interface;
use IO::Socket;
use IPC::Open3;
use List::MoreUtils qw{ any };
use Net::Netmask;
use Pod::Usage;
use Regexp::IPv6 qw($IPv6_re);
use Socket;
use Sys::Hostname;
use YAML::Tiny;
our $VERSION = 'UNRELEASED';
# defaults / option handling {{{
open my $hh, '<', '/etc/hostname'
or croak "Error opening /etc/hostname: $ERRNO";
my $host = <$hh>;
close $hh or croak 'Error closing file handling for /etc/hostname';
chomp $host;
length $host or croak "Fatal error retrieving hostname [$host]";
my $advertised_ip;
my $bond_miimon;
my $bond_mode;
my $bond_slaves;
my $broadcast;
my @dns_nameservers;
my $gateway;
my $help;
my $hwaddr;
my $inputfile = '/etc/ngcp-config/network.yml';
my $internal_iface;
my $ip;
my $ip_v6;
my $man;
my $move_from;
my $move_to;
my $netmask;
my $outputfile = $inputfile;
my $peer;
my @remove_host;
my @remove_interface;
my @roles;
my @set_interface;
my $shared_ip;
my $shared_ip_v6;
my @type;
my $verbose;
my $version;
my $vlan_raw_device;
GetOptions(
'advertised-ip=s' => \$advertised_ip,
'bond-miimon=s' => \$bond_miimon,
'bond-mode=s' => \$bond_mode,
'bond-slaves=s' => \$bond_slaves,
'broadcast=s' => \$broadcast,
'dns=s' => \@dns_nameservers,
'gateway=s' => \$gateway,
'help' => \$help,
'host=s' => \$host,
'hwaddr=s' => \$hwaddr,
'input-file=s' => \$inputfile,
'internal-iface=s' => \$internal_iface,
'ip=s' => \$ip,
'ipv6=s' => \$ip_v6,
'man' => \$man,
'move-from=s' => \$move_from,
'move-to=s' => \$move_to,
'netmask=s' => \$netmask,
'output-file=s' => \$outputfile,
'peer=s' => \$peer,
'remove-host=s' => \@remove_host,
'remove-interface=s' => \@remove_interface,
'role=s' => \@roles,
'set-interface=s' => \@set_interface,
'shared-ip=s' => \$shared_ip,
'shared-ipv6=s' => \$shared_ip_v6,
'type=s' => \@type,
'verbose' => \$verbose,
'version' => \$version,
'vlan-raw-device=s' => \$vlan_raw_device,
) or pod2usage(2);
if ($help) {
pod2usage(0);
}
if ($version) {
print "$PROGRAM_NAME, v$version\n";
exit 0;
}
if ($man) {
pod2usage( -exitstatus => 0, -verbose => 2 );
}
# validate input
if ($ip) {
logger("validating specified IP address $ip");
if ( is_ipv4($ip) || $ip =~ /^(auto|none|delete)$/msx ) {
logger('valid IPv4 address');
}
else {
croak "Specified IP $ip is not a valid IPv4 address";
}
}
if ($ip_v6) {
logger("validating specified IP address $ip_v6");
if ( is_ipv6($ip_v6) || $ip_v6 =~ /^(auto|none|delete)$/msx ) {
logger('valid IPv6 address');
}
else {
croak "Specified IP $ip_v6 is not a valid IPv6 address";
}
}
foreach my $opt (
$bond_miimon, $bond_mode, $broadcast, @dns_nameservers,
$gateway, @set_interface, $host, $hwaddr,
$internal_iface, $ip, $ip_v6, $move_from,
$move_to, $netmask, $peer, @remove_host,
@remove_interface, @roles, @type, $vlan_raw_device
)
{
if ( defined $opt && $opt =~ /\s/msx ) {
logger("invalid option argument $opt");
croak "Command line option does not accept whitespace in '$opt'.";
}
}
# }}}
my $yaml = YAML::Tiny->new;
logger("reading input file $inputfile");
$yaml = YAML::Tiny->read($inputfile)
or croak "File $inputfile could not be read";
if ( -e "$outputfile" && !-w "$outputfile" ) {
croak "Could not open $outputfile for writing (are you user root?)";
}
my $spce;
if ( defined $yaml->[0]->{hosts}->{self} ) {
logger('host "self" identified and set, assuming spce system');
$host = 'self';
$spce = 1;
}
# helper functions {{{
sub logger {
if ($verbose) {
print "@_\n" or croak 'Error sending log output';
}
return;
}
sub get_interface_details {
my $interface = shift or croak "Usage: $PROGRAM_NAME <interface> <setting>";
my $setting = shift or croak "Usage: $PROGRAM_NAME <interface> <setting>";
my $s = IO::Socket::INET->new( Proto => 'tcp' );
return $s->$setting($interface);
}
sub get_ip6_addr {
my $interface = shift or croak 'Usage: runcmd <interface>';
my $cmd = 'ip';
my @args = ( '-6', 'addr', 'show', 'dev', $interface, 'scope', 'global' );
logger("get_ip6_addr for device $interface");
logger("$cmd @args");
my $childpid = open3 'HIS_WRITE', 'HIS_OUT', 'HIS_ERR', $cmd, @args;
my @stderr = <HIS_ERR>;
my @stdout = <HIS_OUT>;
logger("stdout: @stdout");
logger("stderr: @stderr");
close HIS_OUT or croak 'Failed to close stdout';
close HIS_ERR or croak 'Failed to close stderr';
waitpid $childpid, 0;
if ($CHILD_ERROR) {
croak "Problem with execution [return code $CHILD_ERROR]:\n@stderr";
}
foreach my $line (@stdout) {
if ( $line =~ /^\s*inet6\s+($IPv6_re)\/\d+.*scope.*global.*$/msx ) {
return $1;
}
}
return;
}
sub set_interface {
my $iface = shift;
logger("set_interface: interface = $iface");
logger("set_interface: host = $host");
if ( defined $ip && $ip =~ /^auto$/msx ) {
logger("get_interface_details( $iface, 'if_addr' );");
$ip = get_interface_details( $iface, 'if_addr' );
}
if ( defined $ip_v6 && $ip_v6 =~ /^auto$/msx ) {
logger("get_interface_details( $iface, 'if_addr' );");
$ip_v6 = get_ip6_addr($iface);
}
if ( defined $netmask && $netmask =~ /^auto$/msx ) {
logger("get_interface_details( $iface, 'if_netmask' );");
$netmask = get_interface_details( $iface, 'if_netmask' );
}
if ( defined $hwaddr && $hwaddr =~ /^auto$/msx ) {
logger("get_interface_details( $iface, 'if_hwaddr' );");
$hwaddr = get_interface_details( $iface, 'if_hwaddr' );
}
my $settings = {
'advertised_ip' => $advertised_ip,
'bond_miimon' => $bond_miimon,
'bond_mode' => $bond_mode,
'bond_slaves' => $bond_slaves,
'broadcast' => $broadcast,
'gateway' => $gateway,
'hwaddr' => $hwaddr,
'ip' => $ip,
'netmask' => $netmask,
'shared_ip' => $shared_ip,
'shared_v6ip' => $shared_ip_v6,
'v6ip' => $ip_v6,
'vlan_raw_device' => $vlan_raw_device,
};
foreach my $k ( keys %{$settings} ) {
if ( defined $settings->{$k} ) {
if ( $settings->{$k} =~ /^none$/msx ) {
logger("unsetting entry $k");
undef $yaml->[0]->{hosts}->{$host}->{$iface}->{$k};
}
elsif ( $settings->{$k} =~ /^delete$/msx ) {
logger("deleting entry $k");
delete $yaml->[0]->{hosts}->{$host}->{$iface}->{$k};
}
else {
logger("$k: $settings->{$k}");
if($k eq 'shared_ip' || $k eq 'shared_v6ip' || $k eq 'advertised_ip') {
push @{ $yaml->[0]->{hosts}->{$host}->{$iface}->{$k} }, $settings->{$k};
}
else {
$yaml->[0]->{hosts}->{$host}->{$iface}->{$k} = $settings->{$k};
}
}
}
}
if (@dns_nameservers) {
foreach my $dns (@dns_nameservers) {
logger("set_iface_config( $iface, 'dns_nameservers', $dns)");
set_iface_config( $iface, 'dns_nameservers', $dns );
}
}
if (@type) {
foreach my $type (@type) {
logger("set_iface_config( $iface, 'type', $type)");
set_iface_config( $iface, 'type', $type );
}
}
# add interface to list of available interfaces
my $ifaces = $yaml->[0]->{hosts}->{$host}->{interfaces};
if ( !defined $ifaces ) {
logger("no interfaces defined yet, adding interface $iface");
$yaml->[0]->{hosts}->{$host}->{interfaces}->[0] = "$iface";
}
else {
logger("interface = $iface");
if ( any { /^${iface}$/msx } @{$ifaces} ) {
logger("interface $iface already listed on host $host");
}
else {
push @{$ifaces}, $iface;
logger("adding $iface to list of interfaces on host $host");
}
}
return;
}
sub remove_interface {
my $rem_iface = shift or croak 'Usage: remove_interface <interface>';
delete $yaml->[0]->{hosts}->{$host}->{$rem_iface};
my $ifaces = $yaml->[0]->{hosts}->{$host}->{interfaces};
if ( defined $ifaces ) {
logger("removing interface @$ifaces as requested");
undef @{$ifaces};
}
return;
}
sub set_yml_config {
my $setting = shift or croak 'Usage: set_yml_config <setting> <value>';
my $value = shift or croak 'Usage: set_yml_config <setting> <value>';
$yaml->[0]->{hosts}->{$host}->{$setting} = "$value";
logger("\$yaml->[0]->{hosts}->{\$host}->{$setting} = $value");
return;
}
sub set_iface_config {
my $iface = shift
or croak 'Usage: set_iface_config <iface> <setting> <value>';
my $setting = shift
or croak 'Usage: set_iface_config <iface> <setting> <value>';
my $value = shift
or croak 'Usage: set_iface_config <iface> <setting> <value>';
if ( any { /^${value}$/msx }
@{ $yaml->[0]->{hosts}->{$host}->{$iface}->{$setting} } )
{
logger("$value for $setting on $iface already defined in host $host");
}
else {
push @{ $yaml->[0]->{hosts}->{$host}->{$iface}->{$setting} }, $value;
logger(
"\$yaml->[0]->{hosts}->{\$host}->{$iface}->{$setting} => $value");
}
return;
}
sub set_role {
my $new_role = shift or croak 'Usage: set_role <value>';
if ( any { /^${new_role}$/msx } @{ $yaml->[0]->{hosts}->{$host}->{role} } )
{
logger("role $new_role already defined in host $host");
}
else {
push @{ $yaml->[0]->{hosts}->{$host}->{role} }, $new_role;
logger("\$yaml->[0]->{hosts}->{\$host}->{role} => $new_role");
}
return;
}
sub move_settings {
my $from = shift;
my $to = shift;
if ( defined $from && !defined $to ) {
croak '--move-from option must be used with --move-to option together';
}
if ( !defined $from && defined $to ) {
croak '--move-to option must be used with --move-from option together';
}
# ha, nothing to do for us
if ( !defined $from && !defined $to ) {
return;
}
logger("from = $from");
logger("to = $to");
if (@roles) {
foreach my $role (@roles) {
logger("role = $role");
# get rid of the entry from the old section
my @tmp =
grep { !/^${role}$/msx }
@{ $yaml->[0]->{hosts}->{$from}->{role} };
$yaml->[0]->{hosts}->{$from}->{role} = [];
push @{ $yaml->[0]->{hosts}->{$from}->{role} }, @tmp;
# add it to its new place
push @{ $yaml->[0]->{hosts}->{$to}->{role} }, $role;
}
}
if (@type) {
foreach my $type (@type) {
logger("type = $type");
# get rid of the entry from the old section
my @tmp =
grep { !/^${type}$/msx }
@{ $yaml->[0]->{hosts}->{$host}->{$from}->{type} };
$yaml->[0]->{hosts}->{$host}->{$from}->{type} = [];
push @{ $yaml->[0]->{hosts}->{$host}->{$from}->{type} }, @tmp;
# add it to its new place, but only if not already defined yet
if ( any { /^${type}$/msx }
@{ $yaml->[0]->{hosts}->{$host}->{$to}->{type} } )
{
logger("type $type is already defined on host $host, interface $to");
}
else {
push @{ $yaml->[0]->{hosts}->{$host}->{$to}->{type} }, $type;
}
}
}
return;
}
# }}}
# main execution {{{
if (@set_interface) {
foreach my $interface (@set_interface) {
logger("set_interface($interface)");
set_interface($interface);
}
}
if (@remove_host) {
foreach my $rhost (@remove_host) {
logger("removing host $rhost");
delete $yaml->[0]->{hosts}->{$rhost};
}
}
if (@remove_interface) {
foreach my $riface (@remove_interface) {
logger("remove_interface($riface)");
remove_interface($riface);
}
}
if ( @roles && ( !defined $move_from || !defined $move_to ) ) {
foreach my $role (@roles) {
logger("set_role($role)");
set_role($role);
}
}
if ( defined $peer && ( !defined $move_from || !defined $move_to ) ) {
logger("set_yml_config('peer', $peer)");
set_yml_config( 'peer', $peer );
}
if ( defined $internal_iface
&& ( !defined $move_from || !defined $move_to ) )
{
logger("set_yml_config('internal_iface', $internal_iface)");
set_yml_config( 'internal_iface', $internal_iface );
}
move_settings( $move_from, $move_to );
open my $fh, '>', "$outputfile"
or croak "Could not open $outputfile for writing";
logger("writing output file $outputfile");
print {$fh} $yaml->write_string()
or croak "Could not write YAML to $outputfile";
close $fh or croak "Couldn't close '$fh': $OS_ERROR";
# }}}
__END__
=head1 NAME
ngcp-network - command line interface to ngcp's network configuration settings
=head1 SYNOPSIS
ngcp-network <options ...>
=head1 OPTIONS
=over 8
=item B<--advertised-ip=<IP>>
Set advertised_ip configuration to specified argument.
=item B<--bond-miimon=<setting>>
Set bond_miimon configuration to specified argument.
=item B<--bond-mode=<mode>>
Set bond_mode configuration to specified argument.
=item B<--bond-slaves=<slaves>>
Set bond_slaves configuration to specified argument.
=item B<--broadcast=<IP>>
Set broadcast configuration to specified argument.
=item B<--dns=<nameserver>>
Set dns_nameservers configuration to specified argument.
Can be specified multiple times in one single command line.
=item B<--gateway=<IP>>
Set gateway configuration to specified argument.
=item B<--help>
Print the help message and exit.
=item B<--host=<name>>
Apply configuration changes for specified host entry instead of using the
hostname of the currently running system. NOTE: If running the sip:provider CE
edition this configuration option can't be changed as the only configured host
is set to and supposed to be 'self' there.
=item B<--hwaddr=<MAC_address>>
Set hwaddr configuration (MAC address of network device) to specified argument.
=item B<--input-file=<filename>>
Use specified file as input, defaults to /etc/ngcp-config/network.yml if unset.
=item B<--internal-iface=<name>>
Set internal-iface configuration to specified argument.
=item B<--ip=<IP>>
Set ip configuration (IPv4 address) to specified argument. If set to 'auto' and
the selected interface is available on the running host then the IP address will
be determined based on its current settings.
=item B<--ipv6=<IP>>
Set ip configuration (IPv6 address) to specified argument. If set to 'auto' and
the selected interface is available on the running host then the IP address will
be determined based on its current settings.
=item B<--man>
Prints the manual page and exits.
=item B<--move-from=<source>>
Move item from specified level (being host for --role and interface for --type).
The item needs to be chosen via --type or --role. To be used in combination with
--move-to=....
=item B<--move-to=<target>>
Move item to specified level (being host for --role and interface for --type).
The item needs to be chosen via --type or --role. To be used in combination with
--move-to=....
=item B<--netmask=<IP>>
Set netmask configuration to specified argument.
=item B<--output-file=<filename>>
Store resulting file under specified argument. If unset defaults to
/etc/ngcp-config/network.yml.
=item B<--peer=<nodename>>
Set peer configuration (being the corresponding other node in a PRO setup) to
specified argument.
=item B<--remove-host=<host>>
Remove the specified host from the configuration file.
Can be specified multiple times (--remove-host=sp1 --remove-host=sp2 ...).
=item B<--remove-interface=<interface>>
Remove the specified interface from the configuration file.
Can be specified multiple times (--remove-interface=eth5 --remove-interface=eth6 ...).
=item B<--role=<role>>
Set role configuration for host to specified argument.
Can be specified multiple times (--role=lb --role=proxy ...).
=item B<--set-interface=<name>>
Add specified network interface. Can be combined with options like --hwaddr,
--ip, --netmask,... to set specified arguments as configuration options for the
given network interface.
NOTE: If multiple --set-interface options are specified in one command line
(e.g. '--set-interface=lo --set-interface=eth0 --set-interface=eth1') then
options like --hwaddr can't be sanely combined with different settings on
multiple interfaces. Instead invoke ngcp-network with the --set-interface option
mulitple times.
=item B<--shared-ip=<IP>>
Set shared_ip configuration to specified argument.
=item B<--shared-ipv6=<IP>>
Set shared_v6ip configuration to specified argument.
=item B<--type=<name>>
Set type configuration to specified argument.
Can be specified multiple times in one single command line.
=item B<--verbose>
Be more verbose about execution.
=item B<--version>
Display program version and exit.
=item B<--vlan-raw-device=<device>>
Set vlan_raw_device configuration to specified argument.
=back
=head1 DESCRIPTION
B<This program> will read the given input file(s) and do something
useful with the contents thereof.
=head1 USAGE
Usage examples useful especially on sip:provider CE systems:
ngcp-network --set-interface=eth0 --ip=192.168.23.42 --netmask=255.25.255.248
ngcp-network --set-interface=eth1 --ip=auto --netmask=auto
Usage examples useful especially on sip:provider PRO systems:
ngcp-network --set-interface=lo --set-interface=eth0 --set-interface=eth1 --ip=auto --netmask=auto
ngcp-network --peer=sp2
ngcp-network --host=sp2 --peer=sp1
ngcp-network --set-interface=eth1 --ip=auto --netmask=auto
ngcp-network --move-from=lo --move-to=eth1 --type=ha_int
ngcp-network --set-interface=eth1 --host=sp2 --ip=192.168.255.252 --netmask=255.255.255.248 --type=ha_int
Usage examples useful especially on sip:carrier systems:
ngcp-network --host=proxy2 --set-interface=eth0 --ip=192.168.10.42 --netmask=255.255.255.0
=head1 REQUIRED ARGUMENTS
Depending on the setting you are trying to apply there are different sets of
required arguments. Some examples:
--move-from=INTERFACE1 --move-to=INTERFACE2 --type=XXX
Move specified type setting XXX from INTERFACE1 section to INTERFACE2.
--move-from=HOST1 --move-to=HOST2 --role=XXX
Move specified role setting XXX from HOST1 to HOST2.
--set-interface=INTERFACE --ip=[1.2.3.4|auto|none|delete] --netmask=[255.25.255.0|auto|none|delete] ...
Configure IP, netmask,... on specified INTERFACE.
=head1 DIAGNOSTICS
=head2 Unknown option: ...
The specified command line option is not support.
=head2 File ... could not be read ...
The specified input file doesn't exist or can't be read.
=head2 Error opening /etc/hostname: ...
The file /etc/hostname couldn't be read, either because the file doesn't exist
or having wrong file permissions.
=head2 Fatal error retrieving hostname [...]
No valid hostname could not be retrieved from /etc/hostname.
=head2 Specified IP ... is not a valid IPv4 address
The specified IP address is not considered a valid IPv4 address.
=head2 Specified IP ... is not a valid IPv6 address
The specified IP address is not considered a valid IPv6 address.
=head2 Command line option does not accept whitespace in ...
An argument to a command line option contains whitespace(s),
which isn't supported to avoid problems with the YAML file format.
=head2 Could not open [...] for writing (are you user root?)
The configuration file couldn't be stored, usually caused by user executing the
program not having write permissions on the file.
=head2 Error sending log output
Using the --verbose option the more detailed information couldn't be printed to
the console.
=head2 --move-from option must be used with --move-to option together
The --move-from option was specified in the command line but the --move-to
option is missing.
=head2 --move-to option must be used with --move-from option together
The --move-to option was specified in the command line but the --move-from
option is missing.
=head2 Could not open ... for writing
The file can't be written, usually caused because the user doesn't have write
permissions on the file.
=head2 Could not write YAML to ...
There is an error in storing the configuration in the YAML format.
=head1 EXIT STATUS
Exit code 0 means that everything should have went fine.
Exit code 2 means something with the command line options or retrieving default settings went wrong.
Exit code 9 means the specified argument to a command line option is not valid.
=head1 CONFIGURATION
There's no configuration file for the ngcp-network script itself supported at the moment.
The main configuration file ngcp-network operates on is /etc/ngcp-config/network.yml.
=head1 DEPENDENCIES
ngcp-network relies on a bunch of Perl modules, all of them specified as dependencies
through the ngcp-ngcpcfg Debian package.
=head1 INCOMPATIBILITIES
No known at this time.
=head1 BUGS AND LIMITATIONS
Please report problems you notice to the Sipwise Development Team <support@sipwise.com>.
=head1 AUTHOR
Michael Prokop <mprokop@sipwise.com>
=head1 LICENSE AND COPYRIGHT
GPL-3+, Sipwise GmbH, Austria
=cut

@ -0,0 +1,308 @@
#!/usr/bin/perl -w
#----------------------------------------------------------------------
# Syncronizes passwords from constants.yml with MySQL
#----------------------------------------------------------------------
use strict;
use DBI;
use YAML::Tiny;
use Getopt::Long;
use Data::Dumper;
#----------------------------------------------------------------------
use constant CONSTANTS_YML => "/etc/ngcp-config/constants.yml";
use constant MYSQL_CREDENTIALS => "/etc/mysql/sipwise.cnf";
use constant MYSQL_DATA => {
voisniff => { dbuser => 'dbpassword' },
cleanuptools => { dbuser => 'dbpassword' },
rsyslog => { dbuser => 'dbpassword' },
sems => { dbuser => 'dbpassword',
prepaid_dbuser => 'prepaid_dbpassword' },
rateomat => { accountingdb => { user => 'pass' } },
faxserver => { hylafax => { db_user => 'db_pass' } },
cdrexport => { dbuser => 'dbpassword' },
checktools => { dbuser => 'dbpassword' },
mysql => { repuser => 'reppassword' },
kamailio => { proxy => { dbrwuser => 'dbrwpw',
dbrouser => 'dbropw' } },
mediator => { dbuser => 'dbpassword' },
asterisk => { odbc => { dbuser => 'dbpassword' } },
ossbss => { provisioning => {
billingdb => { user => 'pass' } } },
};
use constant COPY_PASSWORDS => [ # pairs of from/to
{ rateomat => { accountingdb => { user => 'pass' }}},
{ rateomat => { billingdb => { user => 'pass' }}},
{ kamailio => { proxy => { dbrwuser => 'dbrwpw' }}},
{ kamailio => { lb => { dbrwuser => 'dbrwpw' }}},
{ kamailio => { proxy => { dbrouser => 'dbropw' }}},
{ kamailio => { lb => { dbrouser => 'dbropw' }}},
{ ossbss => { provisioning => { billingdb => { user => 'pass' }}}},
{ ossbss => { provisioning => { database => { user => 'pass' }}}},
{ ossbss => { provisioning => { billingdb => { user => 'pass' }}}},
{ ossbss => { provisioning => { openserdb => { user => 'pass' }}}},
{ ossbss => { provisioning => { billingdb => { user => 'pass' }}}},
{ reminder => { dbuser => 'dbpassword' }}
];
sub Usage {
print <<USAGE;
==
Syncronizes passwords from constants.yml with MySQL
==
$0 [options]
Options:
-help|-h|-? -- this help
-init-passwords|-i -- generate new passwords (constants.yml is updated)
-test|-t -- test mode (no updates)
-verbose|-v -- verbose mode
USAGE
exit 0;
}
my $dbh;
my $mysql_db = 'mysql';
my $mysql_host = 'localhost';
my $mysql_port = 3360;
my $mysql_user = 'sipwise';
my $mysql_pass = '';
my $yml = {};
my $yml_ref = {};
my $password_length = 20;
my $init_passwords = 0;
my $debug = 0;
my $test_mode = 0;
GetOptions("h|?|help" => \&Usage,
"i|init-passwords" => \$init_passwords,
"t|test" => \$test_mode,
"v|verbose" => \$debug);
#----------------------------------------------------------------------
sub pwgen {
my @list = ("a".."z",0..9,"A".."Z");
my @randoms;
for (1..$password_length) {
push @randoms, $list[int(rand($#list))];
}
return join "", @randoms;
}
sub get_mysql_credentials {
open(my $fh, "<", MYSQL_CREDENTIALS)
or die "Can't open ".MYSQL_CREDENTIALS.": ".$!;
($mysql_pass = <$fh>) =~ s/^.+='(.+?)'\s*$/$1/;
close $fh;
}
sub connect_db {
get_mysql_credentials();
$dbh = DBI->connect("DBI:mysql:database=$mysql_db;
host=$mysql_host;
port=$mysql_port",
$mysql_user, $mysql_pass,
{ PrintError => 0, AutoCommit => 0 })
or die "Can't connect to MySQL database $mysql_db: ". $DBI::errstr;
}
sub sync_mysql_data {
my $sth_sel = $dbh->prepare(<<SQL);
SELECT count(*) from user
WHERE User = ?
SQL
my $sth_upd = $dbh->prepare(<<SQL);
UPDATE user
SET Password=PASSWORD(?)
WHERE User = ?
SQL
foreach my $key (keys %{MYSQL_DATA()}) {
$yml_ref = $yml->[0]->{$key};
print $key." => " if $debug;
my $opts = { init_passwords => $key eq "mysql" ? 0 : $init_passwords };
my $data = get_user_pass(MYSQL_DATA->{$key}, $opts);
foreach my $pair (@$data) {
my $user = $pair->{'user'};
my $pass = $pair->{'pass'};
next unless ($user && $pass);
$sth_sel->execute($user);
(my $count) = $sth_sel->fetchrow_array();
if ($count) {
print " ---> updating $user => $pass\n" if $debug;
$sth_upd->execute($pass, $user) unless $test_mode;
}
}
}
$sth_sel->finish;
$sth_upd->finish;
return if $test_mode;
$dbh->do('FLUSH PRIVILEGES')
or die "Can't flush MySQL privileges: ". $DBI::errstr;
}
sub get_user_pass {
my $h_ref = shift || "No data passed to fetch_mysql_data";
my $opts = shift;
my @data;
foreach my $ref (keys %$h_ref) {
if (ref($ref) eq 'HASH') {
return get_user_pass($ref, $opts);
} elsif (ref($h_ref->{$ref}) eq 'HASH') {
print $ref." => " if $debug;
$yml_ref = $yml_ref->{$ref};
return get_user_pass($h_ref->{$ref}, $opts);
} else {
print " ".$ref." -- ".$h_ref->{$ref} if $debug;
$opts->{'init_passwords'} and $yml_ref->{$h_ref->{$ref}} = pwgen();
my %pair;
$pair{'user'} = $yml_ref->{$ref};
$pair{'pass'} = $yml_ref->{$h_ref->{$ref}};
$pair{'user_key'} = $ref;
$pair{'pass_key'} = $h_ref->{$ref};
push @data, \%pair;
}
}
print "\n" if $debug;
return \@data;
}
sub copy_passwords {
print "Copying internal passwords\n" if $debug;
my $saved_init_passwords = $init_passwords;
$init_passwords = 0;
my $pairs_count = $#{+COPY_PASSWORDS};
for (my $idx=0;$idx<$pairs_count+1;$idx++) {
next if $idx % 2;
die "Incorrect from/to pair" if $idx+1 >= $pairs_count+1;
$yml_ref = $yml->[0];
print "from => " if $debug;
my $from_data = get_user_pass(COPY_PASSWORDS->[$idx]);
die "No 'from' user/pass data available" if $#$from_data == -1;
$yml_ref = $yml->[0];
print "to => " if $debug;
my $to_data = get_user_pass(COPY_PASSWORDS->[$idx+1]);
die "No 'from' user/pass data available" if $#$to_data == -1;
my $user = $from_data->[0]{'user'};
my $pass = $from_data->[0]{'pass'};
my $user_key = $to_data->[0]{'user_key'};
my $pass_key = $to_data->[0]{'pass_key'};
if ($user && $pass && $user_key && $pass_key) {
print " ---> updating $user => $pass\n" if $debug;
$yml_ref->{$user_key} = $user;
$yml_ref->{$pass_key} = $pass;
}
}
$init_passwords = $saved_init_passwords;
}
sub main {
$yml = new YAML::Tiny;
$yml = YAML::Tiny->read(CONSTANTS_YML)
or die "Can't read constants file: $!\n";
if ($init_passwords and not $test_mode and not -w CONSTANTS_YML) {
die CONSTANTS_YML . " is not writable";
}
print "[TEST MODE]\n" if $test_mode;
connect_db();
eval {
$dbh->begin_work;
print "Syncing ".CONSTANTS_YML." -> MySQL ... ";
print "\n" if $debug;
sync_mysql_data();
};
if ($@) {
$dbh->rollback;
die "\nError during syncronization: " . $@;
} else {
$test_mode ? $dbh->rollback : $dbh->commit;
}
$dbh->disconnect if $dbh;
print "Done.\n";
return unless $init_passwords;
copy_passwords();
return if $test_mode;
print "Writing new passwords into ".CONSTANTS_YML." ... ";
$yml->write(CONSTANTS_YML);
print "Done\n";
# print Data::Dumper->Dumpxs([$yml]),"\n";
}
#----------------------------------------------------------------------
main();
exit 0;
__END__
=pod
=head1 NAME
ngcp-sync-constants - syncronizes passwords from constants.yml with MySQL
=head1 SYNOPSIS
ngcp-sync-constants [ options ... ]
=over 8
=item B<--init-passwords>
New passwords are generated (passwords for "mysql" is not generated to avoid replication problems)
=item B<--test>
No real updates, only for checks
=item B<--verbose>
Verbose mode where all changes are written to STDOUT
=back
=head1 DESCRIPTION
B<This program> reads constants.yml file, parses it and syncronizes all required passwords with MySQL
=head1 EXIT STATUS
=over 8
=item B<exit code 0>
Everything is ok
=item B<exit code != 0>
Something is wrong, an error message raises
=back
=head1 INCOMPATIBILITIES
No known at this time.
=head1 BUGS AND LIMITATIONS
Please report problems you notice to the Sipwise Development Team <support@sipwise.com>.
=head1 AUTHOR
Kirill Solomko <ksolomko@sipwise.com>
=head1 LICENSE AND COPYRIGHT
GPL-3+, Sipwise GmbH, Austria
=cut

@ -0,0 +1,147 @@
#!/bin/bash
# Purpose: user interface for configuration management system
################################################################################
set -e
set -u
# support for testsuite
if [ -z "${FUNCTIONS:-}" ] ; then
FUNCTIONS='/usr/share/ngcp-ngcpcfg/functions/'
fi
if [ -z "${SCRIPTS:-}" ] ; then
SCRIPTS='/usr/share/ngcp-ngcpcfg/scripts/'
fi
if ! [ -r "${FUNCTIONS}/main" ] ; then
printf "Error: ${FUNCTIONS}/main could not be read. Exiting.\n" >&2
exit 1
fi
if [[ "${1:-}" == "decrypt" ]] ; then
# do NOT source ${FUNCTIONS}/main but just provide
# the part we need for executing ngcpcfg itself
log_debug() {
if [ -n "${DEBUG:-}" ] ; then
logger -t ngcpcfg -- "Debug: $*"
echo ; echo "DEBUG: $*" ; echo # newlines to avoid messup with cmdline output
fi
}
else
. ${FUNCTIONS}/main
fi
# helper functions
initialise() {
log_debug "${SCRIPTS}/initialise $*"
"${SCRIPTS}"/initialise $*
}
build() {
log_debug "${SCRIPTS}/build $*"
"${SCRIPTS}"/build $*
}
services() {
log_debug "${SCRIPTS}/services $*"
"${SCRIPTS}"/services $*
}
encrypt() {
log_debug "${SCRIPTS}/encrypt $*"
"${SCRIPTS}"/encrypt $*
}
decrypt() {
log_debug "${SCRIPTS}/decrypt $*"
"${SCRIPTS}"/decrypt $*
}
diff() {
log_debug "${SCRIPTS}/diff $*"
"${SCRIPTS}"/diff $*
}
etckeeper() {
log_debug "${SCRIPTS}/etckeeper $*"
"${SCRIPTS}"/etckeeper $*
}
commit() {
log_debug "${SCRIPTS}/commit $*"
"${SCRIPTS}"/commit $*
}
status() {
log_debug "${SCRIPTS}/status $*"
"${SCRIPTS}"/status $*
}
usage() {
# make sure to output errors on stderr
[ "${1:-}" = "1" ] && exec >&2
printf "%s - Configuration Management System\n\n" "$PN"
printf "Usage:
$PN build [opts] - generate/update configuration files
$PN commit [msg] - commit and record changes (without pushing)
$PN diff [opts] - display pending configuration changes
$PN help - display this help screen and exit
$PN version - display program version and exit
$PN initialise - initialise setup (to be executed only once on setup)
"
# display only if ngcp-ngcpcfg-ha is available
if [ -r /usr/share/ngcp-ngcpcfg/functions/ha_features ] ; then
printf " $PN push [opts] - push modifications to other systems (shared storage setup only)\n"
printf " $PN pull - retrieve modifications from shared storage (shared storage setup only)\n"
# printf " $PN upgrade - upgrade all systems [WIP - do not use unless you know what you are doing!]\n"
fi
# display only if ngcp-ngcpcfg-locker is available
if [ -r /usr/share/ngcp-ngcpcfg/scripts/encrypt ] ; then
printf " $PN encrypt - encrypt /etc/ngcp-config and all resulting configuration files\n"
printf " $PN decrypt - decrypt /etc/ngcp-config-crypted.tgz.gpg and restore config files\n"
fi
# display only if ngcp-ngcpcfg-carrier is available
if [ -r /usr/share/ngcp-ngcpcfg/scripts/init-mgmt ] ; then
printf " $PN init-mgmt <srv> - set up mgmgt server for carrier environment (to be executed only once)\n"
fi
printf " $PN services [opts] - execute service handlers for modified configuration files
$PN apply - a short-cut for build-services-commit-etckeeper
$PN status - display status of configuration file\n\n"
printf "For further usage information and options visit the ngcpcfg manpage.\n"
}
version() {
versinfo=$(dpkg --list ngcp-ngcpcfg 2>/dev/null | awk '/^ii/ {print $3}')
[ -n "${versinfo:-}" ] || versinfo='information not available'
printf "ngcpcfg, version ${versinfo}\n"
}
case ${1:-} in
build) shift ; build "$*" ;;
commit) shift ; commit "$*" ;;
initialise) initialise;;
push) shift ; push "$*" ;;
pull) shift ; pull "$*" ;;
services) shift ; services "$*" ;;
status) status;;
apply) shift ; build && services && commit "$*" && etckeeper ;;
encrypt) shift ; encrypt "$*" ;;
decrypt) shift ; decrypt "$*" ;;
upgrade) shift ; upgrade "$*" ;;
diff) shift ; diff "$*" ;;
init-mgmt) shift ; init-mgmt "$*" ;;
--debug) export DEBUG=1 ; shift ; $0 $* ;;
-h|--help|help) usage ; exit 0;;
-v|--version|version) version ; exit 0;;
*) usage 1; exit 1;;
esac
## END OF FILE #################################################################

@ -0,0 +1,129 @@
#!/bin/bash
# Purpose: search for existing .tt2 (template toolkit) files
# and generate configuration files based on ngcpcfg's config
################################################################################
set -e
set -u
# support testsuite
if [ -z "${FUNCTIONS:-}" ] ; then
FUNCTIONS='/usr/share/ngcp-ngcpcfg/functions/'
fi
if [ -z "${HELPER:-}" ] ; then
HELPER='/usr/share/ngcp-ngcpcfg/helper/'
fi
if ! [ -r ${FUNCTIONS}/main ] ; then
printf "Error: ${FUNCTIONS}/main could not be read. Exiting.\n" >&2
exit 1
fi
. ${FUNCTIONS}/main
MODIFIED_ONLY=false
if [ -n "${1:-}" ] ; then
case "$1" in
*--modified-only*) MODIFIED_ONLY=true ; shift ;;
esac
fi
# make sure encoding is OK
for f in ${NGCPCTL_CONFIG:-} ${HOST_CONFIG:-} ${LOCAL_CONFIG:-} ${NETWORK_CONFIG:-} ${CONSTANTS_CONFIG:-} ; do
if [ -r "$f" ] && ! file "$f" | grep -qe "UTF-8" -qe "ASCII" ; then
log_error "Encoding check of ${f} fails: neither ASCII nor UTF-8."
log_error "Please convert ${f} to UTF-8."
log_info
log_info "NOTE:"
log_info "* Check encoding via:"
log_info " # file ${f}"
log_info "* To convert ISO-8859/latin1 to UTF-8 execute:"
log_info " # iconv -f latin1 -t utf8 < ${f} > ${f}.tmp && mv ${f}.tmp ${f}"
exit 1
fi
done
# check for valid YAML syntax
for f in ${NGCPCTL_CONFIG:-} ${HOST_CONFIG:-} ${LOCAL_CONFIG:-} ${NETWORK_CONFIG:-} ${CONSTANTS_CONFIG:-} ; do
if [ -r "$f" ] ; then
# use YAML::Tiny for checking
log_debug "Validating main YAML syntax of ${f}"
if ! "${HELPER}/validate-yml" "${f}" 2>/dev/null ; then
log_error "Invalid file syntax in ${f}:"
"${HELPER}/validate-yml" "${f}"
exit 1
fi
fi
done
build_config_files() {
for file in $(generate_template_list $*) ; do
log_debug "${HELPER}/build_config $file"
"${HELPER}/build_config" "${file}"
RC=$(($RC + $?))
done
}
# main script
RC=0
if ! $MODIFIED_ONLY ; then
build_config_files "$*"
else
log_info "Considering modified files only due to --modified-only option."
if git status | grep -q 'working directory clean' ; then
log_info "No changes found, nothing to do."
exit 0
fi
if git diff-index --name-only HEAD | grep \
-qe "$(basename $NGCPCTL_CONFIG)" \
-qe "$(basename $HOST_CONFIG)" \
-qe "$(basename $LOCAL_CONFIG)" \
-qe "$(basename $NETWORK_CONFIG)" \
-qe "$(basename $CONSTANTS_CONFIG)" ; then
log_info "Main configuation files has been changed, running full rebuild."
log_debug "Executing: build_config_files $*"
build_config_files "$*"
fi
if git diff-index --name-only HEAD | grep -q templates/ || \
git status --porcelain | awk '/^\?\? / {print $2}' 2>/dev/null | grep -q templates/ ; then
log_debug "Template config changed, identifying files."
for file in $(git diff-index --name-only HEAD) \
$(git status --porcelain | awk '/^\?\? / {print $2}') ; do
build_file="${file##templates/}"
build_file="${build_file%%.services}"
build_file="${build_file%%.customtt}"
# drop HA file suffix of all registered nodes
if [ -r /etc/ngcp-config/systems.cfg ] ; then
for host in $(cat /etc/ngcp-config/systems.cfg) ; do
build_file="${build_file%%.${host}}"
done
fi
build_file="${build_file%%.tt2}"
build_file="/${build_file}"
# generate file list
case "${file_list:-}" in
# avoid duplicates
*"${build_file}"*) # do nothing
;;
# append to file list
*) file_list=" ${file_list:-} $build_file"
;;
esac
done
log_debug "Executing: build_config_files ${file_list}"
build_config_files ${file_list}
fi
fi
exit "$RC"
## END OF FILE #################################################################

@ -0,0 +1,67 @@
#!/bin/bash
# Purpose: commit pending changes
################################################################################
set -e
set -u
if ! [ -r /usr/share/ngcp-ngcpcfg/functions/main ] ; then
printf "Error: /usr/share/ngcp-ngcpcfg/functions/main could not be read. Exiting.\n" >&2
exit 1
fi
. /usr/share/ngcp-ngcpcfg/functions/main
if [ -z "${HELPER:-}" ] ; then
HELPER='/usr/share/ngcp-ngcpcfg/helper/'
fi
# main script
cd "$NGCPCTL_MAIN"
"${HELPER}/sync-db" "$NGCPCTL_CONFIG" "$CONSTANTS_CONFIG" || true
if ! git config user.name >/dev/null ; then
log_debug 'git config user.name ngcp-config'
git config user.name "ngcp-config"
fi
if ! git config user.email >/dev/null ; then
log_debug 'git config user.email "root@$(hostname)"'
git config user.email "root@$(hostname)"
fi
if ! git config --global user.name >/dev/null ; then
log_debug 'git config --global user.name "git user on $(hostname)"'
git config --global user.name "git user on $(hostname)"
fi
if ! git config --global user.email >/dev/null ; then
log_debug 'git config --global user.email "root@$(hostname)"'
git config --global user.email "root@$(hostname)"
fi
# commit message
if [ -z "${1:-}" ] ; then
msg="commiting uncommented changes"
else
msg="$*"
fi
log_debug "git status | grep -q 'working directory clean'"
if git status | grep -q 'working directory clean' ; then
log_info "OK: nothing to commit."
else
log_debug 'git add . ; git commit -a -m "$msg [$(date --rfc-3339=ns)]"'
git add .
git commit -a -m "$msg [$(date --rfc-3339=ns)]" >/dev/null
log_info "OK"
fi
log_debug "/usr/share/ngcp-ngcpcfg/scripts/etckeeper"
/usr/share/ngcp-ngcpcfg/scripts/etckeeper >/dev/null
log_info "Synchronizing data from ${CONSTANTS_CONFIG}"
ngcp-sync-constants >/dev/null
## END OF FILE #################################################################

@ -0,0 +1,88 @@
#!/bin/bash
# Purpose: decrypt ngcp configuration archive
################################################################################
set -e
set -u
# helper functions {{{
# sadly we can't source ${FUNCTIONS}/main as we are missing a bunch of
# configuration files that are supposed to be available, therefore
# provide the main functions we need for successfull execution of the
# decrypt function
log_info() {
logger -t ngcpcfg -- "$*"
echo "$*"
}
# info without ending newline
log_info_n() {
logger -t ngcpcfg -- "$*"
printf -- "$*"
}
log_debug() {
if [ -n "${DEBUG:-}" ] ; then
logger -t ngcpcfg -- "Debug: $*"
echo ; echo "DEBUG: $*" ; echo # newlines to avoid messup with cmdline output
fi
}
log_warn() {
logger -t ngcpcfg -- "Warning: $*"
echo "Warning: $*"
}
log_error() {
logger -t ngcpcfg -- "Error: $*"
echo "Error: $*" >&2
}
# }}}
# main script
if ! type -p gpg &>/dev/null ; then
log_error "gpg binary not found, exiting."
exit 1
fi
RC=0
TARGZ=/etc/ngcp-config-crypted.tgz
if ! gpg -d "$TARGZ".gpg > "$TARGZ" ; then
log_error "Error while decrypting ${TARGZ}.gpg"
RC=1
else
cd / # important to extract files at according place
if tar zxf "$TARGZ" ; then
log_info "Successfully restored configuration archive ${TARGZ}.gpg"
log_info "Now you should be able to run 'ngcpcfg apply' again."
else
log_error "Error while restoring ${TARGZ}.gpg"
RC=1
fi
fi
if ! [ -d /mnt/glusterfs/shared_config ] ; then
log_warn "Looks like glusterfs is not running, can not install it automatically.
Please execute the following command on one node
as soon as glusterfs share is mounted again:
git clone --bare /etc/ngcp-config /mnt/glusterfs/ngcpcfg-share
"
else
if [ -d /mnt/glusterfs/ngcpcfg-share ] ; then
log_info "Shared storage exists already, ignoring request to (re)install it."
else
log_info "Copying git repository to shared storage."
git clone --bare /etc/ngcp-config /mnt/glusterfs/ngcpcfg-share
fi
fi
# don't leave the unencrypted archive behind
rm -f "$TARGZ"
exit "$RC"
## END OF FILE #################################################################

@ -0,0 +1,36 @@
#!/bin/bash
# Purpose: show changes in configuration pool
################################################################################
set -e
set -u
if ! [ -r /usr/share/ngcp-ngcpcfg/functions/main ] ; then
printf "Error: /usr/share/ngcp-ngcpcfg/functions/main could not be read. Exiting.\n" >&2
exit 1
fi
. /usr/share/ngcp-ngcpcfg/functions/main
# main script
log_debug "cd $NGCPCTL_MAIN"
cd "$NGCPCTL_MAIN"
log_debug "git diff $*"
git diff $*
# added files
log_debug "git status --porcelain | awk '/^\?\? / {print \$2}'"
if git status --porcelain | awk '/^\?\? / {print $2}' | grep -q . ; then
log_info "* New but not yet registered files inside ${NGCPCTL_MAIN}:"
git status --porcelain | awk '/^\?\? / {print $2}'
fi
# deleted files
log_debug "git status --porcelain | awk '/^D / {print \$2}'"
if git status --porcelain | awk '/^D / {print $2}' | grep -q . ; then
log_info "* Removed but not yet unregistered files inside ${NGCPCTL_MAIN}:"
git status --porcelain | awk '/^D / {print $2}'
fi
## END OF FILE #################################################################

@ -0,0 +1,71 @@
#!/bin/bash
# Purpose: encrypt ngcp configuration files
################################################################################
set -e
set -u
# support testsuite
if [ -z "${FUNCTIONS:-}" ] ; then
FUNCTIONS='/usr/share/ngcp-ngcpcfg/functions/'
fi
if [ -z "${HELPER:-}" ] ; then
HELPER='/usr/share/ngcp-ngcpcfg/helper/'
fi
if ! [ -r ${FUNCTIONS}/main ] ; then
printf "Error: ${FUNCTIONS}/main could not be read. Exiting.\n" >&2
exit 1
fi
. ${FUNCTIONS}/main
get_config_file_list() {
for file in $(find "$TEMPLATE_POOL" -name \*.tt2 -o -name \*.tt2"${HA_FILE:-}") ; do
x=${file##${NGCPCTL_MAIN}/templates/} # drop leading /etc/ngcp-config
y=${x%%.tt2} # drop trailing suffix '.tt2'
y=${y%%.tt2.sp1} # drop trailing suffix '.tt2.sp1'
y=${y%%.tt2.sp2} # drop trailing suffix '.tt2.sp2'
y=${y%%.customtt} # drop trailing suffix '.customtt'
# if the file does not exist (e.g. because "ngcpcfg apply"
# hasn't been executed yet for whatever reason, then don't
# report missing files, otherwise tar will complain
if [ -r "/${y}" ] ; then
echo "/${y}"
fi
done
}
# main script
if ! type -p gpg &>/dev/null ; then
log_error "gpg binary not found, exiting."
exit 1
fi
RC=0
TARGZ=/etc/ngcp-config-crypted.tgz
FILES=$(get_config_file_list)
tar zcf "$TARGZ" /etc/ngcp-config/ $FILES /etc/.git
if gpg --symmetric "$TARGZ" ; then
log_info "Successfully created crypted ngcpcfg configuration archive ${TARGZ}.gpg"
else
log_error "Error while setting up $TARGZ"
RC=1
fi
log_info_n "Now really erase all configuration files managed by ngcpcfg? [y/N] "
a='' ; read a
if [[ "$a" == "y" ]] || [ "$a" == "Y" ]] ; then
rm -rf "$NGCPCTL_MAIN" ; rm -f "$TARGZ" ; rm -f $FILES ; rm -rf /etc/.git
# make sure we don't leavy any stuff on shared storage
rm -rf /var/lib/glusterfs/export/ngcpcfg-share
rm -rf /mnt/glusterfs/ngcpcfg-share/
else
log_info "Skipping as requested."
fi
exit "$RC"
## END OF FILE #################################################################

@ -0,0 +1,41 @@
#!/bin/bash
# Purpose: wrapper around etckeeper for usage inside ngcpcfg
################################################################################
set -e
set -u
if ! [ -r /usr/share/ngcp-ngcpcfg/functions/main ] ; then
printf "Error: /usr/share/ngcp-ngcpcfg/functions/main could not be read. Exiting.\n" >&2
exit 1
fi
. /usr/share/ngcp-ngcpcfg/functions/main
# main script
log_debug "cd /etc"
cd /etc
log_debug "type -p etckeeper"
if ! type -p etckeeper &>/dev/null ; then
log_warn "etckeeper is not available, skipping etckeeper execution"
exit 0
fi
log_debug "test -d .git"
if ! [ -d .git ] ; then
log_warn "etckeeper has not been initialized yet, skipping etckeeper execution"
exit 0
fi
log_info "Checking state of /etc files"
log_debug 'git status | grep -q "working directory clean"'
if git status | grep -q 'working directory clean' ; then
log_info "OK: nothing to commit."
else
log_debug 'etckeeper commit "ngcpcfg apply on $(date)"'
etckeeper commit "ngcpcfg apply on $(date)"
fi
## END OF FILE #################################################################

@ -0,0 +1,78 @@
#!/bin/bash
# Purpose: initialise ngcpcfg setup
################################################################################
set -e
set -u
if ! [ -r /usr/share/ngcp-ngcpcfg/functions/main ] ; then
printf "Error: /usr/share/ngcp-ngcpcfg/functions/main could not be read. Exiting.\n" >&2
exit 1
fi
. /usr/share/ngcp-ngcpcfg/functions/main
# main script
log_debug "cd $NGCPCTL_MAIN"
cd "$NGCPCTL_MAIN"
if [ -d .git ] ; then
log_info "Git directory in $NGCPCTL_MAIN exists already, skipping creation."
else
log_debug "git init"
git init >/dev/null
fi
# ignore files we do not consider as valid template files
if ! grep -qs '^# begin section managed by ngcpcfg' .gitignore ; then
echo '# begin section managed by ngcpcfg (do not edit this section by hand)
# new and old versions of conffiles, stored by dpkg
*.dpkg-*
# new and old versions of conffiles, stored by ucf
*.ucf-*
# old versions of files
*.old
# editor temp files
*~
.*.sw?
.sw?
\#*\#
DEADJOE
# end section managed by ngcpcfg' >> .gitignore
fi
log_debug "git add ."
git add .
if ! git status | grep -q 'working directory clean' ; then
log_debug "git commit -a -m \"initial version of ngcpcfg on $HNAME\""
git commit -a -m "initial version of ngcpcfg on $HNAME" >/dev/null
fi
if type -p init_ha &>/dev/null ; then
log_debug "init_ha function"
init_ha
fi
if ! [ -r /etc/.gitignore ] ; then
log_info "etckeeper not present, ignoring request to add ngcp-config to /etc/.gitignore."
else
log_debug 'grep -q ngcp-config /etc/.gitignore'
if ! grep -q ngcp-config /etc/.gitignore ; then
log_info_n "etckeeper seems to be present, adding "$NGCPCTL_MAIN" to ignore list: "
echo "ngcp-config" >> /etc/.gitignore
log_debug 'cd /etc ; git add .gitignore ; git commit -m "add ngcp-config directory to .gitignore"'
cd /etc
git add .gitignore
git commit -m 'add ngcp-config directory to .gitignore' >/dev/null
log_info "OK"
fi
fi
log_info "Successfully finished setup."
## END OF FILE #################################################################

@ -0,0 +1,98 @@
#!/bin/bash
# Purpose: detect modified files in config tree and execute
# any defined service modifications
################################################################################
set -e
set -u
if ! [ -r /usr/share/ngcp-ngcpcfg/functions/main ] ; then
printf "Error: /usr/share/ngcp-ngcpcfg/functions/main could not be read. Exiting.\n" >&2
exit 1
fi
. /usr/share/ngcp-ngcpcfg/functions/main
# main script
cd "$CONFIG_POOL"
DRYRUN='false'
if [[ "${1:-}" == "test" ]] || [[ "${1:-}" == "--dry-run" ]]; then
DRYRUN='true'
elif [[ -n "${1:-}" ]] ; then
log_error "Unsupported option(s) given: $*"
log_info "Did you mean '--dry-run'?"
exit 1
fi
log_debug "DRYRUN = $DRYRUN"
TMPFILE="$(mktemp)"
# unify service calls
unifyer() {
file="$1"
# make sure services are listed just once to
# avoid re-execution of services (which will
# happen if /etc/foo/ngcpcfg.services exists
# and several file inside /etc/foo are modified)
if ! grep -q "^${file}$" "$TMPFILE" ; then
echo "$file" >> $TMPFILE
fi
}
# NOTES:
# * 'git ls-files -o' also shows ignored files
# * 'git status --porcelain |grep '^?? ' not available in git 1.5
# The 'git diff' command fixes a strange race condition where 'git diff-index'
# lists *all* generated file(s) where the time stamp differs, resulting in a
# list of *all* generated files (which is not what we want).
# After running 'git diff' the following 'git diff-index ...' command lists
# only the modified files as we want and need it. See BTS #211 for bugreport.
git diff &>/dev/null
for file in $(git diff-index --name-only HEAD) ; do
if [ -r "$file" ] && [ -r "${SERVICES_POOL}/${file}".services ] ; then
log_debug "unifyer ${SERVICES_POOL}/${file}.services"
unifyer "${SERVICES_POOL}/${file}".services
elif [ -r "$file" ] && [ -r $SERVICES_POOL/"$(dirname $file)"/ngcpcfg.services ] ; then
log_debug "unifyer ${SERVICES_POOL}/$(dirname $file)/ngcpcfg.services"
unifyer "${SERVICES_POOL}"/"$(dirname $file)/ngcpcfg.services"
fi
done
exec_wrapper() {
# normalize path (get rid of "./" and "//")
line="$(echo $1 | sed -e 's/\.\///g ; s/\/\//\//g')"
if $DRYRUN ; then
log_info "TEST MODE: Would execute action for ${line}"
return 0
fi
log_info "Executing action for $line"
if [ -x "$line" ] ; then
log_debug "$line"
if ! "$line" ; then
log_warn "$line returned with error code, continuing anyway."
fi
elif [ -r "$line" ] ; then
log_debug "bash $line"
if ! bash "$line" ; then
log_warn "$line returned with error code, continuing anyway."
fi
else
log_error "Error: $line could not be read."
exit 1
fi
}
for line in $(cat $TMPFILE) ; do
exec_wrapper "$line"
done
rm -f "$TMPFILE"
## END OF FILE #################################################################

@ -0,0 +1,69 @@
#!/bin/bash
# Purpose: display state of ngcpcfg setup and pending/recommended actions
################################################################################
set -e
set -u
if ! [ -r /usr/share/ngcp-ngcpcfg/functions/main ] ; then
printf "Error: /usr/share/ngcp-ngcpcfg/functions/main could not be read. Exiting.\n" >&2
exit 1
fi
. /usr/share/ngcp-ngcpcfg/functions/main
# main script
if ! [ -d "${NGCPCTL_MAIN:-}" ] ; then
log_error "Directory ${NGCPCTL_MAIN:-} does not exist yet. Execute 'ngcpcfg initialise'."
exit 1
fi
log_debug "cd $NGCPCTL_MAIN"
cd "$NGCPCTL_MAIN"
log_info "Checking state of ngcpcfg:"
if ! [ -r /etc/ngcp-config/.git/HEAD ] ; then
log_warn "ngcpcfg has not been initialised yet. Execute 'ngcpcfg initialise'."
exit 0
fi
log_info "OK: has been initialised already "
log_info "Checking state of configuration files:"
log_debug "git status | grep -q 'working directory clean'"
if git status | grep -q 'working directory clean' ; then
log_info "OK: nothing to commit."
else
if git diff-index --name-only HEAD | grep -q . ; then
log_info "ACTION_NEEDED: configuration files have been modified:"
log_debug "git diff-index --name-only HEAD | sed \"s;^;${NGCPCTL_MAIN}/;\""
git diff-index --name-only HEAD | sed "s;^;${NGCPCTL_MAIN}/;"
fi
if git ls-files --other --exclude-standard | grep -q . ; then
log_info "ACTION_NEEDED: configuration files have been added:"
log_debug "git ls-files --other --exclude-standard | sed \"s;^;${NGCPCTL_MAIN}/;\""
git ls-files --other --exclude-standard | sed "s;^;${NGCPCTL_MAIN}/;"
fi
log_info "-> execute 'ngcpcfg build' and 'ngcpcfg commit'"
fi
if which status_ha &>/dev/null ; then
log_debug "status_ha function"
status_ha
fi
log_debug "cd /etc"
cd /etc
log_info "Checking state of /etc files"
log_debug "git status | grep -q 'working directory clean'"
if git status | grep -q 'working directory clean' ; then
log_info "OK: nothing to commit."
else
log_info "ACTION_NEEDED: configuration files changed (execute 'etckeeper commit [message]')."
fi
## END OF FILE #################################################################

@ -0,0 +1,16 @@
all: prepare test
prepare:
carton install
test:
mkdir -p ../reports/
rm -f ../reports/ngcp-network.tap
bash ./ngcp-network > ../reports/ngcp-network.tap
clean:
rm -rf testfiles
dist-clean: clean
rm -rf ../reports/
rm -rf local

@ -0,0 +1,89 @@
#!/bin/bash
set -e
set -u
# when invoked under DEBUG_SHELL=1 then provide
# interactive shell before exiting
if [ -n "${DEBUG_SHELL:-}" ] ; then
bailout() { bash; exit 1; }
else
bailout() { exit 1; }
fi
export testsuite="$(dirname $PWD/$0)"
TMPDIR="$(mktemp -d)"
echo "Switching to temporary directory $TMPDIR"
cd "$TMPDIR"
cp -a ${testsuite}/* .
export FUNCTIONS="$testsuite/../functions/"
export HELPER="$testsuite/../helper/"
export SCRIPTS="$testsuite/../scripts/"
echo -n "Testing ngcpcfg without any arguments: "
if $testsuite/../sbin/ngcpcfg 2>&1 | grep -q "^Usage:$" ; then
echo OK
else
echo "Error with executing ngcpcfg without any arguments" >&2
bailout
fi
echo -n "Testing ngcpcfg --help: "
if $testsuite/../sbin/ngcpcfg --help 2>&1 | grep -q "^Usage:$" ; then
echo OK
else
echo "Error with executing ngcpcfg --help" >&2
bailout
fi
echo -n "Testing ngcpcfg --version: "
if $testsuite/../sbin/ngcpcfg --version 2>&1 | grep -q "version" ; then
echo OK
else
echo "Error with executing ngcpcfg --version" >&2
bailout
fi
echo "Testing ngcpcfg build:"
$testsuite/../sbin/ngcpcfg build > build.log
oldIFS="$IFS"
IFS="
"
for line in $(cat build.log) ; do
case "$line" in
Generating\ testsuite/*OK) echo generation OK ;;
Executing\ postbuild\ for\ testsuite/*) echo postbuild OK;;
chgrp\ www-data\ testsuite/ngcp-ossbss/logging.conf) echo postbuild OK;;
DEBUG:*) ;; # support running under "--debug"
*)
echo "Error caught: $line" >&2
bailout
;;
esac
done
IFS="$oldIFS"
# test main tt2 processing
if [[ $(cat testsuite/testtemplate) == "foo" ]] ; then
echo "template test is OK"
else
echo "Error with [ngcp-config/templates/]testsuite/testtemplate.tt2" >&2
bailout
fi
# test precedence of files
if [[ $(cat testsuite/precedence/all/test) == "test.custom.tt2" ]] ; then
echo "precedence test is OK"
else
echo "Error with [ngcp-config/templates/]testsuite/precedence/all/*" >&2
bailout
fi
rm -rf "$TMPDIR"
echo "Everything seems to be ok."
# EOF

@ -0,0 +1,13 @@
requires 'Carp';
requires 'Data::Validate::IP';
requires 'Getopt::Long';
requires 'IO::Interface';
requires 'IO::Socket';
requires 'IPC::Open3';
requires 'List::MoreUtils';
requires 'Net::Netmask';
requires 'Pod::Usage';
requires 'Regexp::IPv6';
requires 'Socket';
requires 'Sys::Hostname';
requires 'YAML::Tiny';

@ -0,0 +1,70 @@
---
hosts:
sp1:
eth0:
dns_nameservers:
- 2.3.4.5
- 3.4.5.6
gateway: 1.2.3.1
hwaddr: de:ad:be:ef:23:42
ip: 1.2.3.4
netmask: 255.255.255.0
eth1:
hwaddr: de:ad:be:ef:42:23
ip: 192.168.255.251
netmask: 255.255.255.248
type:
- ha_int
interfaces:
- lo
- eth0
- eth1
lo:
hwaddr: 00:00:00:00:00:00
ip: 127.0.0.1
netmask: 255.0.0.0
shared_ip: ~
shared_v6ip: ~
type:
- sip_int
- web_ext
- sip_ext
- rtp_ext
- ssh_ext
- mon_ext
- web_int
v6ip: '::1'
peer: sp2
role:
- proxy
- lb
- mgmt
sp2:
eth1:
ip: 192.168.255.252
netmask: 255.255.255.248
type:
- ha_int
interfaces:
- lo
- eth1
lo:
hwaddr: 00:00:00:00:00:00
ip: 127.0.0.1
netmask: 255.0.0.0
shared_ip: ~
shared_v6ip: ~
type:
- sip_int
- web_ext
- sip_ext
- rtp_ext
- ssh_ext
- mon_ext
- web_int
v6ip: '::1'
peer: sp1
role:
- proxy
- lb
- mgmt

@ -0,0 +1,24 @@
---
hosts:
sp1:
eth42:
ip: 1.2.3.4
netmask: 255.255.255.248
interfaces:
- lo
- eth42
lo:
ip: 127.0.0.1
netmask: 255.255.255.0
type:
- sip_int
- ha_int
- web_ext
- sip_ext
- rtp_ext
- ssh_ext
- mon_ext
role:
- proxy
- lb
- mgmt

@ -0,0 +1,20 @@
---
hosts:
sp1:
interfaces:
- lo
lo:
ip: 127.0.0.1
netmask: 255.255.255.0
type:
- sip_int
- ha_int
- web_ext
- sip_ext
- rtp_ext
- ssh_ext
- mon_ext
role:
- proxy
- lb
- mgmt

@ -0,0 +1,279 @@
#These values might be changed to constants.yml
networking:
eaddress: 192.168.51.117
ha:
eiface: eth0
bindnetaddr: 192.168.51.0
mcastaddr: 226.94.1.1
mcastport: 5405
database:
bufferpoolsize: 254M
kamailio:
port: 5060
disable_tcp: yes
authenticate_bye: no
multi_homed: no
allow_peer_relay: no
use_enum: no
enum_suffix: e164.arpa.
patterns:
emergency: 112|911|999
asterisk:
sip:
bindport: 5070
dtmfmode: rfc2833
rtp:
minport: 10000
maxport: 20000
voicemail:
serveremail: voicebox@sip.sipwise.com
maxmsg: 30
max_msg_length: 180
min_msg_length: 3
maxgreet: 60
fromstring: Voicemail server
mailsubject: '[Voicebox] New message ${VM_MSGNUM} in voicebox ${VM_MAILBOX}'
mailbody: 'You have received a new message from ${VM_CALLERID} in voicebox ${VM_MAILBOX} on ${VM_DATE}.'
log:
facility: local6
mediator:
interval: 10
rateomat:
splitpeakparts: 0
loopinterval: 10
ossbss:
htpasswd:
- user: ngcpsoap
pass: '{SHA}w4zj3mxbmynIQ1jsUEjSkN2z2pk='
apache:
port: 2443
serveradmin: support@sipwise.com
servername: '"myserver"'
sslcertfile: /etc/apache2/ssl/myserver.crt
sslcertkeyfile: /etc/apache2/ssl/myserver.pem
provisioning:
log_passwords: 0
no_logline_truncate: 0
allow_ip_as_domain: 1
allow_numeric_usernames: 0
tmpdir: /tmp
faxpw_min_char: 0
routing:
cc_regex: '[1-9]\d{0,3}'
ac_regex: '[1-9]\d{0,4}'
sn_regex: '[1-9]\d+'
logging:
ossbss:
facility: local0
level: DEBUG
identity: provisioning
web:
facility: local0
level: DEBUG
apache:
err:
facility: local7
level: info
acc:
facility: daemon
level: info
identity: oss
www_admin:
apache:
port: 1443
serveradmin: support@sipwise.com
servername: '"myserver"'
sslcertfile: /etc/apache2/ssl/myserver.crt
sslcertkeyfile: /etc/apache2/ssl/myserver.pem
billing_features: 1
peering_features: 1
voicemail_features: 1
fax_features: 1
conference_features: 1
cc_dial_prefix: 00
ac_dial_prefix: 0
dashboard:
enabled: 1
subscriber:
extension_features: 0
audiofile_features: 0
domain:
rewrite_features: 1
audiofile_features: 0
vsc_features: 0
default_admin_settings:
is_master: 0
is_active: 1
read_only: 0
show_passwords: 1
call_data: 0
fees_csv:
element_order:
- destination
- zone
- zone_detail
- onpeak_init_rate
- onpeak_init_interval
- onpeak_follow_rate
- onpeak_follow_interval
- offpeak_init_rate
- offpeak_init_interval
- offpeak_follow_rate
- offpeak_follow_interval
- use_free_time
speed_dial_vsc_presets:
vsc:
- '*0'
- '*1'
- '*2'
- '*3'
- '*4'
- '*5'
- '*6'
- '*7'
- '*8'
- '*9'
logging:
apache:
err:
facility: local7
level: info
acc:
facility: daemon
level: info
identity: oss
www_csc:
apache:
port: 443
serveradmin: support@sipwise.com
servername: myserver
sslcertfile: /etc/apache2/ssl/myserver.crt
sslcertkeyfile: /etc/apache2/ssl/myserver.pem
site_domain: sip.yourdomain.tld
display_account_info: 0
sip_server: sip.yourdomain.tld
tftp_server: tftp.yourdomain.tld
payment_features: 0
cc_dial_prefix: 00
ac_dial_prefix: 0
site_config:
title: Sipwise NGCP CSC
default_language: en
default_uri: '/desktop'
languages:
- en
- es
company:
name: Your Company
logo: 'https://some.server/path/to/logo.gif'
hotline: ''
city: ''
street: ''
phone: ''
fax: ''
email: ''
webserver: ''
main_menu:
desktop: 1
calllist: 1
voicebox: 1
addressbook: 1
callforward: 1
callblock: 1
reminder: 1
device: 0
account: 1
logging:
apache:
err:
facility: local7
level: info
acc:
facility: daemon
level: info
identity: csc
rtpproxy:
minport: 30000
maxport: 40000
sems:
bindport: 5080
lowport: 40001
highport: 50000
xmlrpcport: 8090
vsc:
voicemail_number: 2000
cfu_code: 72
cfb_code: 90
cft_code: 92
cfna_code: 93
speedial_code: 50
reminder_code: 55
rsyslog:
external_log: 0
external_address: 192.168.32.1
external_proto: udp
external_port: 514
external_loglevel: warning
reminder:
retries: 2
retry_time: 60
wait_time: 30
sip_fromuser: reminder
sip_fromdomain: voicebox.sipwise.local
checktools:
sip_check_enable: 1
mysql_check_enable: 1
mpt_check_enable: 0
exim_check_enable: 0
kamailio_check_dialog_active_enable: 1
kamailio_check_dialog_early_enable: 0
kamailio_check_usrloc_regusers_enable: 1
kamailio_check_usrloc_regdevices_enable: 0
oss_check_provisioned_subscribers_enable: 1
force: 0
mysql_check_replication: 1
kamailio_check_dialog_local_enable: 0
kamailio_check_dialog_relay_enable: 0
kamailio_check_dialog_incoming_enable: 0
kamailio_check_dialog_outgoing_enable: 0
collcheck:
maxage: 600
cpuidle: 0.1
swapfree: 0.5
dfused: 0.9
memused: 0.7
loadshort: 3
loadmedium: 2
loadlong: 2
siptimeout: 15
eximmaxqueue: 15
cdrexport:
exportpath: '/home/jail/home/cdrexport'
filepreffix: sipwise
fileversion: 001
monthly_folder: yes
daily_folder: yes
cleanuptools:
batch: 10000
archive_targetdir: '/tmp'
compress: gzip
acc_days: 90
trash_days: 30
acc2_days: 180
general:
companyname: sipwise
lang: en
adminmail: nomail@nodomain.org
# vim: ft=yaml

@ -0,0 +1,127 @@
#############################
#
# DO NOT EDIT THIS FILE!!
#
# This file contains some values not being handled by the ngcp configuration framework.
# Editing this file may cause your system to stop working.
# Do not manually edit this file unless you know what you're doing.
#
#
############################
database:
dbhost: localhost
dbport: 3306
kamailio:
dbengine: MYSQL
dbname: kamailio
dbrootuser: root
dbropw: jJXgh7AAmkJ4KCMWYHCX
dbrouser: kamailioro
dbrwpw: g7PYspcXhLRNjgwPghkx
dbrwuser: kamailio
uaccryptpw: UwrpwmpCUMhfv4zscuha
asterisk:
asterisk:
internal_timing: no
odbc:
dbuser: asterisk
dbpassword: cx9W7PWMmkjRVpzzYkts
dbname: kamailio
mediator:
dbuser: mediator
dbpassword: AcMcrhbzXhUmTvTf9gsm
srcdbname: kamailio
destdbname: accounting
provdbname: provisioning
rateomat:
billingdb:
name: billing
user: rateomat
pass: dn7iM9YgPcJhmHXo9eWr
accountingdb:
name: accounting
user: rateomat
pass: dn7iM9YgPcJhmHXo9eWr
mysql:
repuser: replicator
reppassword: KtXpr3jT7jtcd7PmnTbd
ossbss:
provisioning:
database:
name: provisioning
user: soap
pass: hEuxXrzLF43X93ULhoNu
billingdb:
name: billing
user: soap
pass: hEuxXrzLF43X93ULhoNu
openserdb:
name: kamailio
user: soap
pass: hEuxXrzLF43X93ULhoNu
acl:
- user: csc
pass: RMYisfV4rvpWYVKosYnU
allow:
- Voip
- Billing
fax:
sendfax: /usr/bin/sendfax
faxserver: 127.0.0.1
default_sender: webfax
routing:
internal_domain: voip.sipwise.local
no_such_number: no_such_number
voicebox_domain: voicebox.local
fax2mail_domain: fax2mail.local
conference_domain: conference.local
backends:
available:
- Billing
- Voip
enabled:
- Billing
- Voip
www_csc:
prov_user: csc
prov_pass: RMYisfV4rvpWYVKosYnU
sems:
dbuser: soap
dbpassword: hEuxXrzLF43X93ULhoNu
rsyslog:
dbname: syslog
dbuser: rsyslog
dbpassword: bAmjr7gTaevK4tFofkaP
rotate_days: 28
reminder:
context: reminder
sip_peer: sip_proxy
dbname: provisioning
dbuser: soap
dbpassword: hEuxXrzLF43X93ULhoNu
checktools:
dbuser: nagios
dbpassword: XM4s47qEyJrckCoqPVYe
sipuser: nagios
sipdomain: voip.sipwise.local
sip_check_ip: 127.0.0.1
cdrexport:
dbuser: exporter
dbpassword: zghivhVEv7fPMRiLAPRR
dbname: accounting
cleanuptools:
dbuser: dbcleaner
dbpassword: q43aaqRucmTmYz9gvJhe
acc_db: kamailio
trash_db: kamailio
#### Do not touch this! ####
configuration_framework:
constants_version: 4083
config_version: 4083
# vim: ft=yaml

@ -0,0 +1,18 @@
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
59 23 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#

@ -0,0 +1,170 @@
[client]
port = [% database.dbport %]
socket = /var/run/mysqld/mysqld.sock
default_character_set = utf8
#----------------------------------------------------------------
[safe_mysqld]
syslog
#----------------------------------------------------------------
[mysqld]
user = mysql
port = [% database.dbport %]
socket = /var/run/mysqld/mysqld.sock
max_connections = 2048
back_log = 128
max_connect_errors = 1000
connect_timeout = 2
wait_timeout = 60
max_allowed_packet = 16M
net_buffer_length = 8K
default_character_set = utf8
character_set_server = utf8
default_collation = utf8_general_ci
init_connect = 'SET NAMES utf8; SET sql_mode = STRICT_TRANS_TABLES'
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
language = /usr/share/mysql/english
log-error = /var/log/mysql/mysqld.err
pid-file = /var/run/mysqld/mysqld.pid
log_slow_queries = /var/log/mysql/slow-queries.log
log_output = FILE
long_query_time = 5
log_long_format
#log = /var/log/mysql/queries.log
#Binlog options
log_bin = /var/lib/mysql/log-bin
max_binlog_size = 512M
expire_logs_days = 90 #Values 0-99
binlog_format = row
binlog_cache_size = 1M
sync_binlog = 1
relay_log = /var/lib/mysql/log-relay-bin
max_relay_log_size = 512M
#Replication options
server_id = 1
auto_increment_offset = 1
auto_increment_increment = 2
master-host = sp2
master-port=[% database.dbport %]
master-user=[% mysql.repuser %]
master-password=[% mysql.reppassword %]
master-connect-retry=10
replicate-wild-do-table=kamailio.%
replicate-wild-do-table=provisioning.%
replicate-wild-do-table=operating.%
replicate-wild-do-table=billing.%
replicate-wild-do-table=accounting.%
replicate-wild-do-table=syslog.%
replicate-ignore-table=accounting.acc_backup
replicate-ignore-table=accounting.acc_trash
replicate-ignore-table=kamailio.acc_backup
replicate-ignore-table=kamailio.acc_trash
table_cache = 4096
join_buffer_size = 8M
tmp_table_size = 64M
sort_buffer_size = 8M
thread_cache_size = 64
thread_concurrency = 8
thread_stack = 192K
# Query cache, disabled
query_cache_size = 0
query_cache_type = 1
query_cache_limit = 2M
transaction_isolation = REPEATABLE-READ
# MyISAM options
key_buffer_size = 256M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 128M
bulk_insert_buffer_size = 64M
myisam_max_sort_file_size = 10G
myisam_repair_threads = 2
#myisam_recover_options = DEFAULT
# InnoDB options
innodb_data_home_dir = /var/lib/mysql
innodb_data_file_path = ibdata1:10M:autoextend
innodb_file_per_table
innodb_buffer_pool_size = [% database.bufferpoolsize %]
innodb_additional_mem_pool_size = 32M
innodb_log_group_home_dir = /var/lib/mysql
innodb_log_files_in_group = 4
innodb_log_file_size = 128M
innodb_log_buffer_size = 8M
innodb_max_dirty_pages_pct = 80
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 50
innodb_flush_method = O_DIRECT
innodb_thread_concurrency = 32
innodb_autoinc_lock_mode = 1
innodb_locks_unsafe_for_binlog
innodb_fast_shutdown = 1
innodb_max_purge_lag = 0
#----------------------------------------------------------------
[mysqldump]
quick
max_allowed_packet = 16M
single_transaction
#----------------------------------------------------------------
[mysql]
#no_auto_rehash
#----------------------------------------------------------------
[myisamchk]
# databases
key_buffer = 256M
sort_buffer = 256M
read_buffer = 64M
write_buffer = 64M

@ -0,0 +1,170 @@
[client]
port = [% database.dbport %]
socket = /var/run/mysqld/mysqld.sock
default_character_set = utf8
#----------------------------------------------------------------
[safe_mysqld]
syslog
#----------------------------------------------------------------
[mysqld]
user = mysql
port = [% database.dbport %]
socket = /var/run/mysqld/mysqld.sock
max_connections = 2048
back_log = 128
max_connect_errors = 1000
connect_timeout = 2
wait_timeout = 60
max_allowed_packet = 16M
net_buffer_length = 8K
default_character_set = utf8
character_set_server = utf8
default_collation = utf8_general_ci
init_connect = 'SET NAMES utf8; SET sql_mode = STRICT_TRANS_TABLES'
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
language = /usr/share/mysql/english
log-error = /var/log/mysql/mysqld.err
pid-file = /var/run/mysqld/mysqld.pid
log_slow_queries = /var/log/mysql/slow-queries.log
log_output = FILE
long_query_time = 5
log_long_format
#log = /var/log/mysql/queries.log
#Binlog options
log_bin = /var/lib/mysql/log-bin
max_binlog_size = 512M
expire_logs_days = 90 #Values 0-99
binlog_format = row
binlog_cache_size = 1M
sync_binlog = 1
relay_log = /var/lib/mysql/log-relay-bin
max_relay_log_size = 512M
#Replication options
server_id = 2
auto_increment_offset = 2
auto_increment_increment = 2
master-host = sp1
master-port=[% database.dbport %]
master-user=[% mysql.repuser %]
master-password=[% mysql.reppassword %]
master-connect-retry=10
replicate-wild-do-table=kamailio.%
replicate-wild-do-table=provisioning.%
replicate-wild-do-table=operating.%
replicate-wild-do-table=billing.%
replicate-wild-do-table=accounting.%
replicate-wild-do-table=syslog.%
replicate-ignore-table=accounting.acc_backup
replicate-ignore-table=accounting.acc_trash
replicate-ignore-table=kamailio.acc_backup
replicate-ignore-table=kamailio.acc_trash
table_cache = 4096
join_buffer_size = 8M
tmp_table_size = 64M
sort_buffer_size = 8M
thread_cache_size = 64
thread_concurrency = 8
thread_stack = 192K
# Query cache, disabled
query_cache_size = 0
query_cache_type = 1
query_cache_limit = 2M
transaction_isolation = REPEATABLE-READ
# MyISAM options
key_buffer_size = 256M
read_buffer_size = 2M
read_rnd_buffer_size = 8M
myisam_sort_buffer_size = 128M
bulk_insert_buffer_size = 64M
myisam_max_sort_file_size = 10G
myisam_repair_threads = 2
#myisam_recover_options = DEFAULT
# InnoDB options
innodb_data_home_dir = /var/lib/mysql
innodb_data_file_path = ibdata1:10M:autoextend
innodb_file_per_table
innodb_buffer_pool_size = [% database.bufferpoolsize %]
innodb_additional_mem_pool_size = 32M
innodb_log_group_home_dir = /var/lib/mysql
innodb_log_files_in_group = 4
innodb_log_file_size = 128M
innodb_log_buffer_size = 8M
innodb_max_dirty_pages_pct = 80
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 50
innodb_flush_method = O_DIRECT
innodb_thread_concurrency = 32
innodb_autoinc_lock_mode = 1
innodb_locks_unsafe_for_binlog
innodb_fast_shutdown = 1
innodb_max_purge_lag = 0
#----------------------------------------------------------------
[mysqldump]
quick
max_allowed_packet = 16M
single_transaction
#----------------------------------------------------------------
[mysql]
#no_auto_rehash
#----------------------------------------------------------------
[myisamchk]
# databases
key_buffer = 256M
sort_buffer = 256M
read_buffer = 64M
write_buffer = 64M

@ -0,0 +1,6 @@
#!/bin/bash
/etc/init.d/mysql restart
sleep 2
# vim: ft=sh

@ -0,0 +1,16 @@
log4perl.logger.Sipwise.Provisioning = [% ossbss.logging.ossbss.level %], ProvSyslogApp
log4perl.appender.ProvSyslogApp = Log::Dispatch::Syslog
log4perl.appender.ProvSyslogApp.facility = [% ossbss.logging.ossbss.facility %]
log4perl.appender.ProvSyslogApp.ident = [% ossbss.logging.ossbss.identity %]
log4perl.appender.ProvSyslogApp.layout = PatternLayout
log4perl.appender.ProvSyslogApp.layout.ConversionPattern = %M: %m%n
log4perl.logger.Catalyst = WARN, CatalystSyslogApp
log4perl.logger.csc = [% ossbss.logging.web.level %], CatalystSyslogApp
log4perl.logger.admin = [% ossbss.logging.web.level %], CatalystSyslogApp
log4perl.appender.CatalystSyslogApp = Log::Dispatch::Syslog
log4perl.appender.CatalystSyslogApp.facility = [% ossbss.logging.web.facility %]
log4perl.appender.CatalystSyslogApp.layout = PatternLayout

@ -0,0 +1,21 @@
#!/bin/bash
MYSQL_USER='sipwise'
. /etc/mysql/sipwise.cnf
. /etc/ngcp-ossbss/mysql_values.cfg
#dispatcher values reloaded
MYCOM="mysql -u$MYSQL_USER -p$SIPWISE_DB_PASSWORD kamailio -e"
$MYCOM "update dispatcher set destination='sip:$EADDRESS:$ASTERISK_PORT' where setid='2' "
$MYCOM "update dispatcher set destination='sip:$EADDRESS:$SEMS_PORT' where setid='3' "
#xmlrcp values reloaded
#sems ip does not need to change
#kamailio rpc port not configurable at the moment
MYCOM="mysql -u$MYSQL_USER -p$SIPWISE_DB_PASSWORD provisioning -e"
$MYCOM "update xmlhosts set ip='$EADDRESS' where id='1' "
$MYCOM "update xmlhosts set port='$SEMS_XMLRPCPORT' where id='2' "
/etc/init.d/kamailio restart
sleep 2

@ -0,0 +1,4 @@
EADDRESS='[% networking.eaddress %]'
ASTERISK_PORT='[% asterisk.sip.bindport %]'
SEMS_PORT='[% sems.bindport %]'
SEMS_XMLRPCPORT='[% sems.xmlrpcport %]'

@ -0,0 +1,65 @@
<config logconf="/etc/ngcp-ossbss/logging.conf"
usrprefs_as_number="1"
speed_dial_destinations_as_number="1"
log_passwords="[% ossbss.provisioning.log_passwords %]"
no_logline_truncate="[% ossbss.provisioning.no_logline_truncate %]"
allow_ip_as_domain="[% ossbss.provisioning.allow_ip_as_domain %]"
allow_numeric_usernames="[% ossbss.provisioning.allow_numeric_usernames %]"
tmpdir="[% ossbss.provisioning.tmpdir %]"
fax_features="[% www_admin.fax_features %]"
faxpw_min_char="[% ossbss.provisioning.faxpw_min_char %]"
prov_data_typing="1"
voicemail_map_via_number="0"
apache_port="[% ossbss.apache.port %]"
customer_features="0"
product_features="0"
numberblock_features="0"
lnp_features="0"
>
<database dsn="DBI:mysql:database=[% ossbss.provisioning.database.name %];host=[% database.dbhost %];port=[% database.dbport %]"
username="[% ossbss.provisioning.database.user %]"
password="[% ossbss.provisioning.database.pass %]" />
<billingdb dsn="DBI:mysql:database=[% ossbss.provisioning.billingdb.name %];host=[% database.dbhost %];port=[% database.dbport %]"
username="[% ossbss.provisioning.billingdb.user %]"
password="[% ossbss.provisioning.billingdb.pass %]" />
<openserdb dsn="DBI:mysql:database=[% ossbss.provisioning.openserdb.name %];host=[% database.dbhost %];port=[% database.dbport %]"
username="[% ossbss.provisioning.openserdb.user %]"
password="[% ossbss.provisioning.openserdb.pass %]" />
<acl>
[% FOREACH aclentry = ossbss.provisioning.acl %]
<[% aclentry.user %] password="[% aclentry.pass %]" [% FOREACH aclallow = aclentry.allow %][% aclallow %]="" [% END %] />
[% END %]
</acl>
<invoice template="/usr/local/etc/corporate.pdf" />
<fax sendfax="[% ossbss.provisioning.fax.sendfax %]"
faxserver="[% ossbss.provisioning.fax.faxserver %]"
default_sender="[% ossbss.provisioning.fax.default_sender %]" />
<vsc>
<actions>error</actions>
<actions>unknown</actions>
<actions>cfu_on</actions>
<actions>cfu_off</actions>
<actions>cfb_on</actions>
<actions>cfb_off</actions>
<actions>cft_on</actions>
<actions>cft_off</actions>
<actions>cfna_on</actions>
<actions>cfna_off</actions>
<actions>reminder_on</actions>
<actions>reminder_off</actions>
</vsc>
<routing internal_domain="[% ossbss.provisioning.routing.internal_domain %]"
no_such_number="[% ossbss.provisioning.routing.no_such_number %]"
voicebox_domain="[% ossbss.provisioning.routing.voicebox_domain %]"
fax2mail_domain="[% ossbss.provisioning.routing.fax2mail_domain %]"
conference_domain="[% ossbss.provisioning.routing.conference_domain %]"
cc_regex="[% ossbss.provisioning.routing.cc_regex %]"
ac_regex="[% ossbss.provisioning.routing.ac_regex %]"
sn_regex="[% ossbss.provisioning.routing.sn_regex %]"
/>
<reserved_usernames>voicebox</reserved_usernames>
<system rrd_path="/var/lib/collectd/rrd" />
[% FOREACH backend = ossbss.provisioning.backends.enabled %]
<backends_enabled>[% backend %]</backends_enabled>
[% END %]
</config>

@ -0,0 +1,4 @@
[% FOREACH htentry = ossbss.htpasswd %]
[% htentry.user %]:[% htentry.pass %]
[% END %]

@ -0,0 +1,40 @@
<config debugging="0"
log4perlconf="/etc/ngcp-ossbss/logging.conf"
billing_features="[% www_admin.billing_features %]"
peering_features="[% www_admin.peering_features %]"
voicemail_features="[% www_admin.voicemail_features %]"
fax_features="[% www_admin.fax_features %]"
conference_features="[% www_admin.conference_features %]"
customer_features="0"
product_features="0"
numberblock_features="0"
lnp_features="0"
cc_dial_prefix="[% www_admin.cc_dial_prefix %]"
ac_dial_prefix="[% www_admin.ac_dial_prefix %]"
voicebox_domain="[% ossbss.provisioning.routing.voicebox_domain %]"
fax2mail_domain="[% ossbss.provisioning.routing.fax2mail_domain %]"
conference_domain="[% ossbss.provisioning.routing.conference_domain %]"
>
<dashboard enabled="[% www_admin.dashboard.enabled %]" />
<subscriber extension_features="[% www_admin.subscriber.extension_features %]"
audiofile_features="[% www_admin.subscriber.audiofile_features %]"
/>
<domain rewrite_features="[% www_admin.domain.rewrite_features %]"
audiofile_features="[% www_admin.domain.audiofile_features %]"
vsc_features="[% www_admin.domain.vsc_features %]"
/>
<default_admin_settings is_master="[% www_admin.default_admin_settings.is_master %]" is_active="[% www_admin.default_admin_settings.is_active %]"
read_only="[% www_admin.default_admin_settings.read_only %]" show_passwords="[% www_admin.default_admin_settings.show_passwords %]"
call_data="[% www_admin.default_admin_settings.call_data %]" />
<fees_csv>
[% FOREACH feecsvelement = www_admin.fees_csv.element_order %]
<element_order>[% feecsvelement %]</element_order>
[% END %]
</fees_csv>
<speed_dial_vsc_presets>
[% FOREACH speeddialvsc = www_admin.speed_dial_vsc_presets.vsc %]
<vsc>[% speeddialvsc %]</vsc>
[% END %]
</speed_dial_vsc_presets>
</config>

@ -0,0 +1,120 @@
#!/bin/bash
# defaults
if [ -d local ] ; then # running with carton
CMD="perl -Ilocal/lib/perl5 -CSD ../sbin/ngcp-network"
else
CMD="perl -CSD ../sbin/ngcp-network"
fi
count=0
RC=0
OUTPUT=$(mktemp) || exit 1
# generated files
rm -rf testfiles
mkdir testfiles
bailout() {
rm -f "$OUTPUT"
}
trap bailout 1 2 3 3 6 9 14 15
OK() {
printf "ok ${1} ${2}\n"
}
FAIL() {
printf "not ok ${1} ${2}\n"
RC=1
}
assertEqualFiles() {
[ "$#" -eq 2 ] || return 1
(( count++ ))
if cmp "$1" "$2" 2>/dev/null ; then
OK "$count" "$2" >> "$OUTPUT"
else
echo "files $1 and $2 do not match" >&2
FAIL "$count" "$2 # $2 differs from $1" >> "$OUTPUT"
return 1
fi
}
# make sure ip/netmask/interface can be set on exisiting host
${CMD} --input-file=network-config/network_pro.yml --output-file=testfiles/eth42.yml \
--host=sp1 --set-interface=eth42 --ip=1.2.3.4 --netmask=255.255.255.248
assertEqualFiles testfiles/eth42.yml network-config/eth42.yml
# verify deployment steps
ROLE=sp1; PEER=sp2; DEFAULT_INSTALL_DEV=eth0; INTERNAL_DEV=eth1;
in_counter=1; out_counter=1 # do not hardcode input/output files
${CMD} --host=$ROLE --set-interface=lo --ip=127.0.0.1 --netmask=255.0.0.0 \
--hwaddr=00:00:00:00:00:00 --ipv6='::1' --type=web_int \
--input-file=network-config/network_pro.yml --output-file=testfiles/deploy_${out_counter}.yml
((out_counter++))
${CMD} --host=$ROLE --set-interface=lo --shared-ip=none --shared-ipv6=none \
--input-file=testfiles/deploy_${in_counter}.yml --output-file=testfiles/deploy_${out_counter}.yml
((out_counter++)) ; ((in_counter++))
${CMD} --host=$ROLE --set-interface=$DEFAULT_INSTALL_DEV --ip=1.2.3.4 \
--netmask=255.255.255.0 --hwaddr=de:ad:be:ef:23:42 --dns=2.3.4.5 --dns=3.4.5.6 \
--gateway=1.2.3.1 \
--input-file=testfiles/deploy_${in_counter}.yml --output-file=testfiles/deploy_${out_counter}.yml
((out_counter++)) ; ((in_counter++))
${CMD} --host=$ROLE --set-interface=$INTERNAL_DEV --ip=192.168.255.251 \
--netmask=255.255.255.248 --hwaddr=de:ad:be:ef:42:23 \
--input-file=testfiles/deploy_${in_counter}.yml --output-file=testfiles/deploy_${out_counter}.yml
((out_counter++)) ; ((in_counter++))
${CMD} --host=$ROLE --peer=$PEER \
--input-file=testfiles/deploy_${in_counter}.yml --output-file=testfiles/deploy_${out_counter}.yml
((out_counter++)) ; ((in_counter++))
${CMD} --host=$ROLE --move-from=lo --move-to=$INTERNAL_DEV --type=ha_int \
--input-file=testfiles/deploy_${in_counter}.yml --output-file=testfiles/deploy_${out_counter}.yml
((out_counter++)) ; ((in_counter++))
${CMD} --host=$PEER --peer=$ROLE \
--input-file=testfiles/deploy_${in_counter}.yml --output-file=testfiles/deploy_${out_counter}.yml
((out_counter++)) ; ((in_counter++))
${CMD} --host=$PEER --set-interface=lo --shared-ip=none --shared-ipv6=none \
--input-file=testfiles/deploy_${in_counter}.yml --output-file=testfiles/deploy_${out_counter}.yml
((out_counter++)) ; ((in_counter++))
${CMD} --host=$PEER --set-interface=lo --ipv6='::1' --ip=127.0.0.1 --netmask=255.0.0.0 --hwaddr=00:00:00:00:00:00 \
--input-file=testfiles/deploy_${in_counter}.yml --output-file=testfiles/deploy_${out_counter}.yml
((out_counter++)) ; ((in_counter++))
${CMD} --host=$PEER --set-interface=eth1 --ip=192.168.255.252 --netmask=255.255.255.248 --type=ha_int \
--input-file=testfiles/deploy_${in_counter}.yml --output-file=testfiles/deploy_${out_counter}.yml
((out_counter++)) ; ((in_counter++))
${CMD} --host=$PEER --role=proxy --role=lb --role=mgmt \
--input-file=testfiles/deploy_${in_counter}.yml --output-file=testfiles/deploy_${out_counter}.yml
((out_counter++)) ; ((in_counter++))
${CMD} --host=$PEER --set-interface=lo --type=sip_int --type=web_ext --type=sip_ext \
--type=rtp_ext --type=ssh_ext --type=mon_ext --type=web_int \
--input-file=testfiles/deploy_${in_counter}.yml --output-file=testfiles/deployment.yml
assertEqualFiles testfiles/deployment.yml network-config/deployment.yml
# TAP output
printf "1..$count\n"
cat "$OUTPUT"
bailout
exit $RC

@ -0,0 +1,31 @@
# Filename: /etc/ngcp-config/ngcpcfg.cfg
# Purpose: main configuration file for ngcpcfg tools
# Note: do not modify unless you have a really good reason to do so
# directory name where ngcpcfg is managed through git
NGCPCTL_MAIN='./ngcp-config'
NGCPCTL_CONFIG="${NGCPCTL_MAIN}/config.yml"
HOST_CONFIG="${NGCPCTL_MAIN}/config.$(hostname).yml"
LOCAL_CONFIG="${NGCPCTL_MAIN}/config.local.yml"
CONSTANTS_CONFIG="${NGCPCTL_MAIN}/constants.yml"
# configuration files that should be managed
CONFIG_POOL='/tmp/output'
# location of templates
TEMPLATE_POOL="${NGCPCTL_MAIN}/templates/testsuite"
# location of service definitions
SERVICES_POOL="${NGCPCTL_MAIN}/templates/testsuite"
## NOTE: only supported with ngcp-ngcpcfg-ha
# supported values: {true,false}
SHARED_STORAGE='true'
# name of shared storage
GLUSTERFS='./glusterfs'
# name of shared storage repository
NGCPCTL_SHARE="${GLUSTERFS}/ngcpcfg-share"
## END OF FILE #################################################################
Loading…
Cancel
Save