diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Dockerfile | 40 | ||||
-rw-r--r-- | entrypoint.sh | 20 | ||||
-rw-r--r-- | murmur-info.py | 186 | ||||
-rwxr-xr-x | murmur-munin.py | 214 | ||||
-rwxr-xr-x | userparameter_murmur.conf | 2 |
6 files changed, 248 insertions, 215 deletions
@@ -1 +1,2 @@ *~ +.* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5fd5435 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +FROM python:3.7-alpine + +# zeroc-ice +ARG ICE_VERSION=3.7.2 +RUN set -ex \ + && apk add --no-cache \ + libstdc++ \ + openssl-dev \ + && apk add --no-cache --virtual .build-deps \ + bzip2-dev \ + g++ \ + && pip install --global-option=build_ext --global-option="-D__USE_UNIX98" zeroc-ice==${ICE_VERSION} \ + && apk del .build-deps \ + && find /usr/local -depth \ + \( \ + \( -type d -a \( -name test -o -name tests \) \) \ + -o \ + \( -type f -a \( -name '*.pyc' -o -name '*.pyo' \) \) \ + \) -exec rm -rf '{}' +; + +# SSH server and bash +RUN apk --update add --upgrade --no-cache openssh bash + +COPY entrypoint.sh /entrypoint.sh +COPY Murmur.ice /murmur-info/Murmur.ice +COPY murmur-info.py /murmur-info/murmur-info.py + +RUN chmod +x /entrypoint.sh \ + && mkdir -p /root/.ssh \ + && rm -rf /var/cache/apk/* /tmp/* + +ENV OPENSSH_VERSION=${OPENSSH_VERSION} \ + ROOT_PASSWORD=root \ + KEYPAIR_LOGIN=false + +VOLUME ["/etc/ssh"] + +EXPOSE 22 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..5b92c87 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# generate host keys if not present +ssh-keygen -A + +# set root login mode by password or keypair +if [ "${KEYPAIR_LOGIN}" = "true" ] && [ -f "${HOME}/.ssh/authorized_keys" ] ; then + sed -i "s/#PermitRootLogin.*/PermitRootLogin without-password/" /etc/ssh/sshd_config + sed -i "s/#PasswordAuthentication.*/PasswordAuthentication no/" /etc/ssh/sshd_config + echo "Enabled root-login by keypair and disabled password-login" +else + sed -i s/#PermitRootLogin.*/PermitRootLogin\ yes/ /etc/ssh/sshd_config + if [ -n "${ROOT_PASSWORD}" ] && [ "${ROOT_PASSWORD}" != "root" ]; then + echo "root:${ROOT_PASSWORD}" | chpasswd + fi + echo "Enabled root-login by password" +fi + +# do not detach (-D), log to stderr (-e), passthrough other arguments +exec /usr/sbin/sshd -D -e "$@"
\ No newline at end of file diff --git a/murmur-info.py b/murmur-info.py new file mode 100644 index 0000000..a2a0b42 --- /dev/null +++ b/murmur-info.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +# -*- coding: utf-8 +# +# munin-info.py - "murmur stats (User/Bans/Uptime/Channels)" script. +# Copyright (c) 2019, Charles Lu / c4planted@gmail.com +# Adapted from Natenom's murmur-munin.py +# Copyright (c) 2014, Natenom / natenom@natenom.name +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of the developer nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +import Ice, sys, os + +class MurmurIce: + + def __init__(self, murmur_ice_path, murmur_host, murmur_icesecreatread, ice_port=6502, message_size_max=65535): + + # Exclude names containing these keywords from being counted as users. + # Useful for excluding bots + self.exclude_keywords=["Delay","BBUBot","PeiPeiBot"] + + # Path to Slice and Murmur.ice + Ice.loadSlice(f"--all -I{Ice.getSliceDir()} {murmur_ice_path}") + + props = Ice.createProperties([]) + # MessageSizeMax; increase this value, if you get a MemoryLimitException. + # Also check this value in murmur.ini of your Mumble-Server. + # This value is being interpreted in kibiBytes. + props.setProperty("Ice.MessageSizeMax", str(message_size_max)) + props.setProperty("Ice.ImplicitContext", "Shared") + props.setProperty("Ice.Default.EncodingVersion", "1.0") # Murmur 1.2.x uses Ice protocl 1.0 only + + id = Ice.InitializationData() + id.properties = props + + self.ice = Ice.initialize(id) + + # Ice Password to get read access. + # If there is no such var in your murmur.ini, this can have any value. + # You can use the values of icesecret, icesecretread or icesecretwrite in your murmur.ini + self.ice.getImplicitContext().put("secret", murmur_icesecreatread) + + import Murmur + + try: + # Murmur host IP/DNS and ice_port should be provided + self.meta = Murmur.MetaPrx.checkedCast(self.ice.stringToProxy(f'Meta:tcp -h {murmur_host} -p {ice_port}')) + except (Ice.DNSException, Ice.ConnectionRefusedException): + print('Connection refused.') + exit(1) + + try: + self.server=self.meta.getServer(1) + except Murmur.InvalidSecretException: + print('Given icesecreatread password is wrong.') + exit(1) + + self.users = 0 + self.excludedusers = 0 + self.usersnotauth = 0 + + self._count_users() + + def __del__(self): + self.ice.destroy() + + def _count_users(self): + # count users + self.users = self.server.getUsers() + # count the number of users to exclude + # also count not authenticated users (who are not excluded) + for user in self.users.values(): + for keyword in self.exclude_keywords: + if keyword in user.name: + self.excludedusers += 1 + break + else: + # not excluded + if user.userid == -1: + self.usersnotauth += 1 + + def get_all_values(self): + print(f"users: {(len(self.users)-self.excludedusers)}") + print(f"uptime: {self.meta.getUptime()}") + print(f"chancount: {(len(self.server.getChannels())-1)}") + print(f"bancount: {len(self.server.getBans())}") + print(f"usersnotauth: {self.usersnotauth}") + print("state: 1") + print(f'version: {self.meta.getVersion()[0]}.{self.meta.getVersion()[1]}.{self.meta.getVersion()[2]}') + + def get_value(self, key): + if key == "users": + print(len(self.users)-self.excludedusers) + + elif key == "uptime": + print(self.meta.getUptime()) + + elif key == "chancount": + print(len(self.server.getChannels())-1) + + elif key == "bancount": + print(len(self.server.getBans())) + + elif key == "usersnotauth": + print(self.usersnotauth) + + elif key == "state": + print(1) + + elif key == "version": + print(f'{self.meta.getVersion()[0]}.{self.meta.getVersion()[1]}.{self.meta.getVersion()[2]}') + + elif key == "useronline" and len(sys.argv) == 3: + for key in self.users.keys(): + if sys.argv[2].lower() == self.users[key].name.lower(): + print(1) + break + else: + print(0) + else: + self.get_all_values() + + +if __name__ == "__main__": + + murmur_ice_path = os.getenv('MURMUR_ICE_PATH') + murmur_host = os.getenv('MURMUR_HOST', '127.0.0.1') + ice_port = os.getenv('MURMUR_ICE_PORT', 6502) + murmur_icesecreatread = os.getenv('MURMUR_ICE_SECRET') + message_size_max = os.getenv('MURMUR_ICE_MSG_SIZE_MAX', 65535) + + if murmur_ice_path is None: + raise RuntimeError('MURMUR_ICE_PATH environment variable is not set!') + if murmur_icesecreatread is None: + raise RuntimeError('MURMUR_ICE_SECRET environment variable is not set!') + + murmur = MurmurIce( + murmur_ice_path=murmur_ice_path, + murmur_host=murmur_host, + murmur_icesecreatread=murmur_icesecreatread, + ice_port=ice_port, + message_size_max=message_size_max, + ) + + # Usage + if sys.argv[1:]: + if sys.argv[1] == "help": + print('useronline [name]: Checks if the user with the name provided is online') + print('users: Number of users online') + print('usersnotauth: Number of users online (Not authenticated)') + print('uptime: Uptime in seconds') + print('chancount: Channel count') + print('bancount: Bans on server') + print("state: Mumble server status") + print("version: Mumble server version") + + else: + murmur.get_value(sys.argv[1]) + + else: + murmur.get_all_values() diff --git a/murmur-munin.py b/murmur-munin.py deleted file mode 100755 index 99846cd..0000000 --- a/murmur-munin.py +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -# -# munin-murmur.py - "murmur stats (User/Bans/Uptime/Channels)" script for munin. -# Copyright (c) 2014, Natenom / natenom@natenom.name -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of the developer nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - - - -#Path to Murmur.ice -iceslice='/usr/share/Ice/slice/Murmur.ice' - -#Includepath for Ice, this is default for Debian -iceincludepath="/usr/share/Ice/slice" - -#Murmur-Port (not needed to work, only for display purposes) -serverport=64738 - -#Port where ice listen -iceport=6502 - -#Ice Password to get read access. -#If there is no such var in your murmur.ini, this can have any value. -#You can use the values of icesecret, icesecretread or icesecretwrite in your murmur.ini -icesecret="Ac8unPPK7u" - -#MessageSizeMax; increase this value, if you get a MemoryLimitException. -# Also check this value in murmur.ini of your Mumble-Server. -# This value is being interpreted in kibiBytes. -messagesizemax="65535" - -#Exclude names containing these keywords from being counted as users. -#Useful for excluding bots -exclude_keywords=["Delay","BBUBot","PeiPeiBot"] - -import Ice, sys -Ice.loadSlice("--all -I%s %s" % (iceincludepath, iceslice)) - -props = Ice.createProperties([]) -props.setProperty("Ice.MessageSizeMax", str(messagesizemax)) -props.setProperty("Ice.ImplicitContext", "Shared") -id = Ice.InitializationData() -id.properties = props - -ice = Ice.initialize(id) -ice.getImplicitContext().put("secret", icesecret) - -import Murmur - -if (sys.argv[1:]): - if (sys.argv[1] == "config"): - print 'graph_title Murmur (Port %s)' % (serverport) - print 'graph_vlabel Count' - print 'users.label Users' - print 'usersnotauth.label Users (Not authenticated)' - print 'uptime.label Uptime in days' - print 'chancount.label Channelcount' - print 'bancount.label Bans on server' - print "state.label Mumble server status" - print "version.label Mumble server version" - sys.exit(0) - - -try: - meta = Murmur.MetaPrx.checkedCast(ice.stringToProxy("Meta:tcp -h 127.0.0.1 -p %s" % (iceport))) -except Ice.ConnectionRefusedException: - if (sys.argv[1:]): - if (sys.argv[1] == "users"): - print "users.value 0" - ice.shutdown() - sys.exit(1) - elif (sys.argv[1] == "uptime"): - print "uptime.value 0" - ice.shutdown() - sys.exit(1) - elif (sys.argv[1] == "chancount"): - print "chancount.value 0" - ice.shutdown() - sys.exit(1) - elif (sys.argv[1] == "bancount"): - print "bancount.value 0" - ice.shutdown() - sys.exit(1) - elif (sys.argv[1] == "usersnotauth"): - print "usersnotauth.value 0" - ice.shutdown() - sys.exit(1) - elif (sys.argv[1] == "state"): - print "state.value 0" - ice.shutdown() - sys.exit(1) - elif (sys.argv[1] == "version"): - print "version.value 0" - ice.shutdown() - sys.exit(1) - - print "users.value 0" - print "uptime.value 0" - print "chancount.value 0" - print "bancount.value 0" - print "usersnotauth.value 0" - print "state.value 0" - print "version.value 0" - ice.shutdown() - sys.exit(1) - -try: - server=meta.getServer(1) -except Murmur.InvalidSecretException: - print 'Given icesecreatread password is wrong.' - ice.shutdown() - sys.exit(1) - -#count users -users=server.getUsers() - -#count the number of users to exclude -#also count not authenticated users (who are not excluded) -excludedusers=0 -usersnotauth=0 -exluded=False -for key in users.keys(): - for name_keyword in exclude_keywords: - if (name_keyword in users[key].name): - excludedusers+=1 - exluded=True - if (users[key].userid == -1 and not exluded): - usersnotauth+=1 - exluded=False - -#get the version number of the server -mumbleversion='' -dummy='' -# more argument parsing for individual stats -if (sys.argv[1:]): - if (sys.argv[1] == "users"): - print "users.value %i" % (len(users)-excludedusers) - ice.shutdown() - sys.exit(0) - elif (sys.argv[1] == "uptime"): - print "uptime.value %i" % (float(meta.getUptime())) - ice.shutdown() - sys.exit(0) - elif (sys.argv[1] == "chancount"): - print "chancount.value %i" % (len(server.getChannels())-1) - ice.shutdown() - sys.exit(0) - elif (sys.argv[1] == "bancount"): - print "bancount.value %i" % (len(server.getBans())) - ice.shutdown() - sys.exit(0) - elif (sys.argv[1] == "usersnotauth"): - print "usersnotauth.value %i" % (usersnotauth) - ice.shutdown() - sys.exit(0) - elif (sys.argv[1] == "state"): - print "state.value 1" - ice.shutdown() - sys.exit(0) - elif (sys.argv[1] == "version"): - print "version.value %i.%i.%i" % (meta.getVersion()[0],meta.getVersion()[1],meta.getVersion()[2]) - ice.shutdown() - sys.exit(0) - elif (sys.argv[1] == "useronline" and len(sys.argv) > 2): - user_online_flag = False - for key in users.keys(): - if(sys.argv[2].lower() == users[key].name.lower()): - user_online_flag = True - if (user_online_flag): - print "useronline.value 1" - else: - print "useronline.value 0" - ice.shutdown() - sys.exit(0) - # TODO - -# if no command line argument is passed in -print "users.value %i" % (len(users)-excludedusers) -print "uptime.value %i" % (float(meta.getUptime())) -print "chancount.value %i" % (len(server.getChannels())-1) -print "bancount.value %i" % (len(server.getBans())) -print "usersnotauth.value %i" % (usersnotauth) -print "state.value 1" -print "version.value %i.%i.%i" % (meta.getVersion()[0],meta.getVersion()[1],meta.getVersion()[2]) - -ice.shutdown() diff --git a/userparameter_murmur.conf b/userparameter_murmur.conf index d9c327c..d455dc4 100755 --- a/userparameter_murmur.conf +++ b/userparameter_murmur.conf @@ -1,2 +1,2 @@ # Zabbix agent custom keys -UserParameter=murmur.value[*],/home/charles/murmur/murmur-info/murmur-munin.py $1 $2 | awk '{print $$2}'
\ No newline at end of file +UserParameter=murmur.value[*],/home/charles/murmur/murmur-info/murmur-munin.py $1 $2
\ No newline at end of file |