Espresso.Bin Firewall

After installing Armbian I was running into network issues which could be solved with:

systemctl unmask systemd-networkd; systemctl start systemd-networkd

https://wiki.archlinux.org/title/Systemd-networkd#Wired_adapter_using_a_static_IP

root@ebin:/etc/systemd/network# cat 10-br0.network

[Match]
Name=br0

[Network]
Address=10.1.10.9/24
Gateway=10.1.10.1
DNS=10.1.10.1
#DNS=8.8.8.8
[Match]
Name = br0

[Network]
Address = 192.168.179.23 / 24
Gateway = 192.168.179.1
DNS = 192.168.179.1
# DNS = 8.8.8.8

development environment

summary

  • create folder on server as: repo--dev.git
  • initialize git repo: git init –bare
  • create folder on local machine
  • get files from remote repo: git clone ssh://git@olkn.myvnc.com/repo--dev.git
  • add files to staging: git add -A
  • commit changes to repo: git commit -m “
  • push changes to remote repo: git push origin

git

config

  • git config –global user.name “olkn”
  • git config –global user.email “olkn@gmail.com”
  • git remote add olkn ssh://olkn.myvnc.com/git/repo-python-development
  • git config –global pull.rebase true
  • git config –global color.ui auto
  • git config –global core.editor vim
  • .gitignore to list all files that should not be included in git repo

initialise git repo

git init

git init –bare : if the repo is on a server and no working tree is necessary (should end in .git)

stage

Staging adds file to a stage prepared for later commit

  • git add -A
  • git stage .

commit

All files in staging were added/committed to the repo

git commit -m “Comment for commit”

password less login

ssh-keygen -t rsa -b 4096 -C “

ssh-add .ssh/id-rsa

ssh-copy-id -i .ssh/id-rsa @

initialise git repo

mkdir

cd

git init –bare –shared

add files to repo

git add -A

git commit -m “

add remote repo

git remote add live ssh://@/

git push live

docker

docker build -t : build the given image based on Dockerfile

docker images : list all available docker images in the system

docker run -it : run interactive mode image

docker run -d -p 5000:5000 : run image in daemon mode with ports exposed

docker ps : show all running docker container

docker start/stop : start/stop a container

docker-compose up -d : start docker environment detached

docker-composer down : stop all containers

docker-composer ps : list all running containers

docker-composer build : build images from scratch

docke-compose logs : show the log files for a container

python

project folder
— docker-compose.yml
–|– app (program sources we are working on)
—-|– Dockerfile
—-|– requirements.txt
—-|– src
——-|– python.py
–|– db (data base server and config, if any)
—–|– password.txt
–|– web (web server and config, if any)

docker composer file


ersion: "3.7"
services:
db:
image: mysql:8.0.19
command: '--default-authentication-plugin=mysql_native_password'
restart: always
secrets:
- db-password
volumes:
- db-data:/var/lib/mysql
networks:
- backend-network
environment:
- MYSQL_DATABASE=example
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password

app:
build: app
restart: always
secrets:
- db-password
networks:
- backend-network
- frontend-network
volumes:
- ./app/src:/code
ports: (debugger ports for flask inside the container)
- 5678:5678

web:
build: web
restart: always
ports:
- 80:80
networks:
- frontend-network
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
networks:
backend-network:
frontend-network:

docker-file


# set base image (host OS)
FROM python:3.8

# set the working directory in the container
WORKDIR /code

# copy the dependencies file to the working directory
COPY requirements.txt .

# install dependencies
RUN pip install -r requirements.txt

# copy the content of the local src directory to the working directory
COPY src/ .

# command to run on container start
CMD [ "python", "./server.py" ]

laravel

laravel with sail

  • install docker compose
  • install composer: wget https://getcomposer.org/installer

initialize a new project

curl -s https://laravel.build/project-name?with=mysql,selenium,mailhog |bash

configuration

edit .env

docker composer file

docker-compose.yml

docker-file

programming

python

laravel

alternative

python

  • python3 -m venv
  • source /bin/activate

git

  • git init . (executed in folder of course
  • create .gitignore with contents (*.pyc and __pycache__)

README

create a file README with project description and usage instructions

markdown format (README.md) would be a good choice for the formatting

git commit

  • git add .gitignore README.md
  • git add *
  • git comit -m “initial release”

skeleton

file structure

  • folder docs – program documentation (spinx)
  • folder src/app – source code of the application
  • folder tests – unit test files
  • .gitignore – see above
  • requirements.txt – pip requirements file
  • README.md – see above
  • TODO.md – open issues to implement
  • LICENSE – ???
  • setup.py – see below

program skeleton

structure with functions, classes, modules, etc but with docstrings only as the contents will follow later with the implementation

create the main file, e.g. .py


""" descriptive text"""
import sys

"""definition of constants"""
URL = "https://olkn.myvnc.com"

def main():
""" main entry point for the program """
pass

"""definition of functions"""
def get_url(url):
"""describe function"""
pass

if __name__ == '__main__'
sys.exit(main())

requirements

list all the requirements in a file: pip freeze requirements.txt

solr – managed-schema field definitions

name type description active flags deactive flags
ignored_* string catchall for all undefined metadata multiValued
id string unique id field stored, required multiValued
_version_ plong internal solr field indexed, stored
text text_general content field for facetting multiValued docValues, stored
content text_general main content field as extracted by tika stored, multiValued, indexed docValues
author string author retrieved from tika multiValued, indexed, docValues stored
*author string dynamic field for authors retrieved from tika multiValued, indexed, docValues stored
title string title retrieved from tika multiValued, indexed, docValues stored
*title string dynamic title field retrieved from tika multiValued, indexed, docValues stored
date string date retrieved from tika multiValued, indexed, docValues stored
content_type plongs content_type retrieved from tika multiValued, indexed, docValues stored
stream_size string stream_size retrieved from tika multiValued, indexed, docValues stored
cat string category defined by user through manifoldcf multiValued, docValues stored

Additional copyField statements to insert data in fields:

  • source=”content” dest=”text”
  • source=”*author” dest=”author”
  • source=”*title” dest=”title”

solr search server with tika and manifoldcf

I finally managed to get my search server running using solr as main engine and tika for extraction. The setup is competed by a manifoldcf for access to files, emails, wiki, rss and web.

solr

A short overview on the basic file structure of solr is shown below:

filestructure


<solr-home-directory/
solr.xml
core_name1/
core.properties
conf/
solrconfig.xml
managed-schema
data/

And here is my core.properties file without cloud on a single server and very basic as well.

core.properties


Name=collection name
Config=solrconfig.xml
dataDir=collection name/data

schema fields from tika

The following fields are essential for my setup:

  • id – the identifier unique for solr
  • _version_ – also some internal stuff for solr
  • content – the text representation of the extraction results from tika
  • ignored_* – as a catchall for any metadata that is not covered by a field in the index

The solr install is following the instructions given by the project team. As I am using debian the solr.in.sh is barely standard. Here are the settings:


SOLR_PID_DIR="/var/solr"
SOLR_HOME="/var/solr/data"
LOG4J_PROPS="/var/solr/log4j2.xml"
SOLR_LOGS_DIR="/var/solr/logs"
SOLR_PORT="8983"

Solr is started via old init.d style script from the project team. No modifications here.

The specific managed-schema and solrconfig.xml files are not listed here but took the most time to get them running. Some comments:

  • grab some information on the metadata extracted by tika to find the fields that should be worth a second look
  • check for the configuration given in /var/solr/data/conf/
  • especially the solr log at /var/solr/logs/solr.log
  • managed-schema shoud be adjusted for the metadata retrived through tika
  • delete any old collection files by removing /var/solr/data/collection name/collection name/index/
  • solr cell is responsible for importing/indexing files in foreign formats like PDF, Word, etc
  • set stored false as often as possible
  • set indexed false as much as possible
  • remove copyfields as far as possible
  • set indexed false for text_general
  • use catchall field for indexing
  • start JVM in server mode
  • set logging on higher level only
  • integrate everything in tomcat
  • set indexed or docValues to true but not both
  • some field type annottations: Solr Manual 8.11

some interesting commands

  • /bin/solr start
  • /bin/solr stop -all
  • /bin/post -c collection input
  • /bin/solr delete -c collection
  • /bin/solr create -c collection -d configdir
  • velocity setup

    velocity may be used as a search interface for solr but my setup is not completed yet.

    tika

    The tika server version is also installed as described by the project team. I only added a start script for systemd as follows:


    [Unit]
    Description=Apache Tika Server
    After=network.target

    [Service]
    Type=simple
    User=tika
    Environment="TIKA_INCLUDE=/etc/default/tika.in.sh"
    ExecStart=/usr/bin/java -jar /opt/tika/tika-server-standard-2.3.0.jar --port 9998 --config /opt/tika/tika-config.xml
    Restart=always

    [Install]
    WantedBy=multi-user.target

    The tika.in.sh is once again copied from project team suggestion without modifications:


    TIKA_PID_DIR="/var/tika"
    LOG4J_PROPS="/var/tika/log4j.properties"
    TIKA_LOGS_DIR="/var/tika/logs"
    TIKA_PORT="9998"
    TIKA_FORKED_OPTS=""

    The tika-config.xml is quit empty at the moment but I hope to get logging running soon.

    ManifoldCF

    And finally the manifoldcf installation from scratch as the interface to the various information resources.

    and here is my systemd start script:

    [Unit]
    Description=ManifoldCF service
    [Service]
    WorkingDirectory=/opt/manifoldcf/example
    ExecStart=/usr/bin/java -Xms512m -Xmx512m -Dorg.apache.manifoldcf.configfile=./properties.xml -Dorg.apache.manifoldcf.jettyshutdowntoken=secret_token -Djava.security.auth.login.config= -cp .:../lib/mcf-core.jar:../lib/mcf-agents.jar:../lib/mcf-pull-agent.jar:../lib/mcf-ui-core.jar:../lib/mcf-jetty-runner.jar:../lib/jetty-client-9.4.25.v20191220.jar:../lib/jetty-continuation-9.4.25.v20191220.jar:../lib/jetty-http-9.4.25.v20191220.jar:../lib/jetty-io-9.4.25.v20191220.jar:../lib/jetty-jndi-9.4.25.v20191220.jar:../lib/jetty-jsp-9.2.30.v20200428.jar:../lib/jetty-jsp-jdt-2.3.3.jar:../lib/jetty-plus-9.4.25.v20191220.jar:../lib/jetty-schemas-3.1.M0.jar:../lib/jetty-security-9.4.25.v20191220.jar:../lib/jetty-server-9.4.25.v20191220.jar:../lib/jetty-servlet-9.4.25.v20191220.jar:../lib/jetty-util-9.4.25.v20191220.jar:../lib/jetty-webapp-9.4.25.v20191220.jar:../lib/jetty-xml-9.4.25.v20191220.jar:../lib/commons-codec-1.10.jar:../lib/commons-collections-3.2.2.jar:../lib/commons-collections4-4.2.jar:../lib/commons-discovery-0.5.jar:../lib/commons-el-1.0.jar:../lib/commons-exec-1.3.jar:../lib/commons-fileupload-1.3.3.jar:../lib/commons-io-2.5.jar:../lib/commons-lang-2.6.jar:../lib/commons-lang3-3.9.jar:../lib/commons-logging-1.2.jar:../lib/ecj-4.3.1.jar:../lib/gson-2.8.0.jar:../lib/guava-25.1-jre.jar:../lib/httpclient-4.5.8.jar:../lib/httpcore-4.4.10.jar:../lib/jasper-6.0.35.jar:../lib/jasper-el-6.0.35.jar:../lib/javax.servlet-api-3.1.0.jar:../lib/jna-5.3.1.jar:../lib/jna-platform-5.3.1.jar:../lib/json-simple-1.1.1.jar:../lib/jsp-api-2.1-glassfish-2.1.v20091210.jar:../lib/juli-6.0.35.jar:../lib/log4j-1.2-api-2.4.1.jar:../lib/log4j-api-2.4.1.jar:../lib/log4j-core-2.4.1.jar:../lib/mail-1.4.5.jar:../lib/serializer-2.7.1.jar:../lib/slf4j-api-1.7.25.jar:../lib/slf4j-simple-1.7.25.jar:../lib/velocity-1.7.jar:../lib/xalan-2.7.1.jar:../lib/xercesImpl-2.10.0.jar:../lib/xml-apis-1.4.01.jar:../lib/zookeeper-3.4.10.jar:../lib/javax.activation-1.2.0.jar:../lib/javax.activation-api-1.2.0.jar: -jar start.jar
    User=solr
    Type=simple
    SuccessExitStatus=143
    TimeoutStopSec=10
    Restart=on-failure
    RestartSec=10
    [Install]
    WantedBy=multi-user.target

docker web dev

To simplify the development I tried docker for building the runtime environment. Here are the major steps to get it running.

Prerequisites

The docker installation is straight forward as described on the docker home page:

un-install old version

aptitude remove docker docker-engine docker.io

add reporitory

aptitude update

aptitude install apt-transport-https ca-certificates curl gnupg2 software-properties-common

add docker official key

curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -

check fingerprint

apt-key fingerprint 0EBFCD88

add repository

add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"

aptitude update

install docker from repo

aptitude install docker-ce

check if everything works

docker run hello-world

install docker compose

curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

chmod +x /usr/local/bin/docker-compose

and check everything works

docker-compose --version

Docker Cheat Sheet

## List Docker CLI commands
docker
docker container –help

## Display Docker version and info
docker –version
docker version
docker info

## Execute Docker image
docker run hello-world

## List Docker images
docker image ls

## List Docker containers (running, all, all in quiet mode)
docker container ls
docker container ls –all
docker container ls -aq

Development Environment

create folder for docker environment

mkdir dockerproject

create yaml file for docker compose

vi docker-compose.yaml

At least the following sections should be available:

  • app
  • main application configuration

  • web
  • Webserver configuration is required

  • database
  • database configuration is required

and here comes an exmaple


version: '3'
services:
app:
build:
context: ./
dockerfile: app.dockerfile
working_dir: /var/www
volumes:
- ./../laravel:/var/www
environment:
- "DB_PORT=3306"
- "DB_HOST=database"
web:
build:
context: ./
dockerfile: web.dockerfile
working_dir: /var/www
volumes:
- ./../laravel:/var/www
ports:
- 8080:80
database:
image: mysql:5.6
volumes:
- dbdata:/var/lib/mysql
environment:
- "MYSQL_DATABASE=homestead"
- "MYSQL_USER=homestead"
- "MYSQL_PASSWORD=secret"
- "MYSQL_ROOT_PASSWORD=secret"
ports:
- "33061:3306"
volumes:
dbdata:

and now the app configuration


FROM php:7.1.3-fpm

RUN apt-get update
RUN apt-get install -y libmcrypt-dev
RUN apt-get install -y mysql-client
RUN apt-get install -y libmagickwand-dev --no-install-recommends
RUN pecl install imagick
RUN docker-php-ext-enable imagick
RUN docker-php-ext-install mcrypt pdo_mysql
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('SHA384', 'composer-setup.php') === '544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer
RUN apt-get install -y git
RUN apt-get update && apt-get install -y zlib1g-dev
RUN docker-php-ext-install zip

the web configuration


FROM nginx:1.10

ADD vhost.conf /etc/nginx/conf.d/default.conf

DPF – lcd4linux config

lcd4linux.conf

Layout 'Dockstar'

Display 'DPF'

Variables {
# Ticks:
second 1000
minute 60 * second

# Standard Dimensions:
linesize 53 # max line length, for status lines etc.
width100 51 # full width after padding (border)
width050 24 # 1/2 of full width
width033 17 # 1/3 of full width
width025 12 # 1/4 of full width
width010 5 # 1/10 of full width

# Colors:
# ToDo: Alphakanal ausnutzen
black '000000'
white 'ffffff'
red 'ff0000'
darkblue '000066'
lightgray 'b2b2b2'
darkgray '191919'
barcolor0 '5f5fff'
barcolor1 'ff5f5c'

# To be set later by timers:
SyslogMsg 'Dummy'
}

Display dpf {
Driver 'DPF'
Port 'usb0'
Font '6x8'
Foreground white
Background darkblue
Basecolor darkblue
}

Widget System {
class 'Text'
expression '*** ' . uname('nodename') . ' '. netinfo::ipaddr('eth0') . ' ' .
uname('machine') . ' ' . uname('release') . ' ***'
width linesize
align 'C'
update 0
Background lightgray
Foreground darkgray
}

Widget Time {
class 'Text'
expression strftime('%a, %d.%m.%Y -- %H:%M:%S', time()) . ' -- Up: ' . uptim
e('%d days %H:%M:%S')
width linesize
align 'C'
update 1 * second
Background lightgray
Foreground darkgray
}

Widget Busy {
class 'Text'
expression proc_stat::cpu('busy', 0.5 * second)
prefix 'Busy'
postfix '%'
width width050
precision 1
align 'R'
update 0.5 * second
}

Widget BusyBar {
class 'Bar'
expression proc_stat::cpu('busy', 0.5 * second)
expression2 proc_stat::cpu('system', 0.5 * second)
length width050
direction 'E'
update 0.5 * second
Background darkgray
BarColor0 barcolor0
BarColor1 barcolor1
}

Widget Load {
class 'Text'
expression loadavg(1)
prefix 'Load'
postfix loadavg(1) > 1.0 ? '!' : ' '
width width050
precision 1
align 'R'
update 0.5 * second
# Foreground loadavg(1) > 1.0 ? red : white
}

Widget LoadBar {
class 'Bar'
expression loadavg(1)
max 4.0
length width050
direction 'E'
update 0.5 * second
Background darkgray
BarColor0 barcolor0
BarColor1 barcolor1
}

Widget Disk {
class 'Text'
# disk.[rw]blk return blocks, we assume a blocksize of 512
# to get the number in kB/s we would do blk*512/1024, which is blk/2
# expression (proc_stat::disk('.*', 'rblk', 0.5 * second)+proc_stat::disk('.
*', 'wblk', 0.5 * second))/2
# with kernel 2.6, disk_io disappeared from /proc/stat but moved to /proc/di
skstat
# therefore you have to use another function called 'diskstats':
expression (diskstats('sd[a-z]$', 'read_sectors', 0.5 * second) + diskstats(
'sd[a-z]$', 'write_sectors', 0.5 * second)) / 2 / 1024
prefix 'Disk'
postfix ' MB/s'
width width050
precision 1
align 'R'
update 0.5 * second
}

Widget DiskBar {
class 'Bar'
#expression proc_stat::disk('.*', 'rblk', 0.5 * second)
#expression2 proc_stat::disk('.*', 'wblk', 0.5 * second)
# for kernel 2.6:
expression diskstats('sd[a-z]$', 'read_sectors', 0.5 * second) / 2 / 1024
expression2 diskstats('sd[a-z]$', 'write_sectors', 0.5 * second) / 2 / 1024
length width050
direction 'E'
update 0.5 * second
Background darkgray
BarColor0 barcolor0
BarColor1 barcolor1
}

Widget Eth0 {
class 'Text'
expression (netdev('eth0', 'Rx_bytes', 0.5 * second) + netdev('eth0', 'Tx_by
tes', 0.5 * second)) * 8 / 1024 / 1024
prefix 'eth0'
postfix ' Mbit/s'
width width050
precision 1
align 'R'
update 0.5 * second
}

Widget Eth0Bar {
class 'Bar'
expression netdev('eth0', 'Rx_bytes', 0.5 * second) * 8 / 1024 / 1024
expression2 netdev('eth0', 'Tx_bytes', 0.5 * second) * 8 / 1024 / 1024
length width050
direction 'E'
update 0.5 * second
Background darkgray
BarColor0 barcolor0
BarColor1 barcolor1
}

Widget DVB {
class 'Text'
expression dvb('signal_strength') * 100
prefix 'DVB Signal'
postfix '%'
width width050
precision 1
align 'R'
update 0.5 * second
}

Widget DVBBar {
class 'Bar'
expression dvb('signal_strength')
expression2 dvb('snr')
# expression2 dvb('ber')
min 0
max 1
length width050
direction 'E'
update 0.5 * second
Background darkgray
BarColor0 barcolor0
BarColor1 barcolor1
}

Widget MemoryTitle {
class 'Text'
expression 'Memory'
width width050
align 'L'
update 0
}

Widget MemoryTotal {
class 'Text'
expression meminfo('MemTotal') / 1024
prefix 'Total '
postfix ' MB'
width width050
precision 0
align 'R'
update 0
}

Widget MemoryFree {
class 'Text'
expression (meminfo('MemFree') + meminfo('Cached')) / 1024
prefix 'Free '
postfix ' MB'
width width050
precision 0
align 'R'
update 1 * second
}

Widget MemorySwapped {
class 'Text'
expression (meminfo('SwapTotal') - meminfo('SwapFree')) / 1024
prefix 'Swap used '
postfix ' MB'
width width050
precision 0
align 'R'
update 1 * second
}

Widget HDDTempTitle {
class 'Text'
expression 'Disk Temperature°C'
width width050
align 'L'
update 0
}

Widget HDDTemp1 {
class 'Text'
expression hddtemp('/dev/sda')
width width010
precision 1
align 'R'
update 10 * second
}

Widget HDDTemp2 {
class 'Text'
expression hddtemp('/dev/sdb')
width width010
precision 1
align 'R'
update 10 * second
}

Widget HDDTemp3 {
class 'Text'
expression hddtemp('/dev/sdc')
width width010
precision 1
align 'R'
update 10 * second
}

Widget FSSpaceTitle {
class 'Text'
expression 'Disk Space available'
width width050
align 'L'
update 0
}

Widget FSSpace1 {
class 'Text'
expression statfs('/', 'bavail') * statfs('/', 'bsize') / 1024 / 1024 / 1024
prefix '/ (Root FS)'
postfix ' GB'
width width050
precision 2
align 'R'
update 10 * second
}

Widget FSSpace2 {
class 'Text'
expression statfs('/home', 'bavail') * statfs('/home', 'bsize') / 1024 / 102
4 / 1024
prefix '/home'
postfix ' GB'
width width050
precision 2
align 'R'
update 10 * second
}

Widget FSSpace3 {
class 'Text'
expression statfs('/backup', 'bavail') * statfs('/backup', 'bsize') / 1024 /
1024 / 1024
prefix '/backup '
postfix ' GB'
width width050
precision 2
align 'R'
update 10 * second
}

Widget FSSpace4 {
class 'Text'
expression statfs('/mnt/platte', 'bavail') * statfs('/mnt/platte', 'bsize')
/ 1024 / 1024 / 1024
prefix '/platte '
postfix ' GB'
width width050
precision 2
align 'R'
update 10 * second
}

Widget FSSpace5 {
class 'Text'
expression statfs('/mnt/var', 'bavail') * statfs('/mnt/var', 'bsize') / 1024
/ 1024 / 1024
prefix '/var '
postfix ' GB'
width width050
precision 2
align 'R'
update 10 * second
}

Widget ServicesTitle {
class 'Text'
expression 'Services'
width width100
align 'C'
Background lightgray
Foreground darkgray
}

Widget PortmapStatus {
class 'Text'
expression 'Portmap '
width width050
postfix strstr(exec('/etc/init.d/portmap status', 10 * second), 'running') >
0 ? 'up' : 'down!'
update 10 * second
}

Widget SSHdStatus {
class 'Text'
expression 'SSHd '
width width050
postfix strstr(exec('/etc/init.d/ssh status', 10 * second), 'running') > 0 ?
'up' : 'down!'
update 10 * second
}

Widget RsyslogStatus {
class 'Text'
expression 'Rsyslog '
width width050
postfix strstr(exec('/etc/init.d/rsyslog status', 10 * second), 'running') >
0 ? 'up' : 'down!'
update 10 * second
}

Widget pyloadStatus {
class 'Text'
expression 'pyload'
width width050
postfix strstr(exec('/etc/init.d/pyload status', 10 * second), 'running') >
0 ? 'up' : 'down!'
update 10 * second
}

Widget NFSdStatus {
class 'Text'
expression 'NFSd '
width width050
postfix strstr(exec('/etc/init.d/nfs-kernel-server status', 10 * second), 'r
unning') > 0 ? 'up' : 'down!'
update 10 * second
}

Widget LighttpdStatus {
class 'Text'
expression 'Lighttpd '
width width050
postfix strstr(exec('/etc/init.d/lighttpd status', 10 * second), 'running')
> 0 ? 'up' : 'down!'
update 10 * second
}

Widget MiniDLNAStatus {
class 'Text'
expression 'MiniDLNA '
width width050
postfix strstr(exec('/etc/init.d/minidlna status', 10 * second), 'running')
> 0 ? 'up' : 'down!'
update 10 * second
}

Widget MySQLStatus {
class 'Text'
expression 'MySQL '
width width050
postfix strstr(exec('/sbin/status mysql', 10 * second), 'running') > 0 ? 'up
' : 'down!'
update 10 * second
}

Widget MythTVStatus {
class 'Text'
expression 'MythTV Backend '
width width050
postfix strstr(exec('/sbin/status mythtv-backend', 10 * second), 'running')
> 0 ? 'up' : 'down!'
update 10 * second
}

Widget PostfixStatus {
class 'Text'
expression 'Postfix '
width width050
postfix strstr(exec('/etc/init.d/postfix status', 10 * second), 'not running
') > 0 ? 'down!' : 'up'
update 10 * second
}

Widget ProFTPStatus {
class 'Text'
expression 'ProFTP '
width width050
postfix strstr(exec('/etc/init.d/proftpd status', 10 * second), 'not running
') > 0 ? 'down!' : 'up'
update 10 * second
}

Widget SambaStatus {
class 'Text'
expression 'Samba '
width width050
postfix strstr(exec('/sbin/status smbd', 10 * second), 'running') > 0 ? 'up'
: 'down!'
update 10 * second
}

Widget SambaStatusDS {
class 'Text'
expression 'Samba '
width width050
postfix strstr(exec('/etc/init.d/samba status', 10 * second), 'running') > 0
? 'up' : 'down!'
update 10 * second
}

Widget SSHStatus {
class 'Text'
expression 'SSH '
width width050
postfix strstr(exec('/sbin/status ssh', 10 * second), 'running') > 0 ? 'up'
: 'down!'
update 10 * second
}

Widget SSHStatusDS {
class 'Text'
expression 'SSH '
width width050
postfix strstr(exec('/etc/init.d/ssh status', 10 * second), 'running') > 0 ?
'up' : 'down!'
update 10 * second
}

Widget SWRAIDStatus {
class 'Text'
expression 'SW RAID '
width width050
postfix strstr(exec('cat /proc/mdstat', 10 * second), '[UUU]') > 0 ? 'up' :
'attention!'
update 10 * second
}

Widget TwonkyStatus {
class 'Text'
expression 'Twonkymedia '
width width050
postfix strstr(exec('/sbin/status twonkymedia', 10 * second), 'running') > 0
? 'up' : 'down!'
update 10 * second
}

Widget SyslogTitle {
class 'Text'
expression '/var/log/syslog'
width width100
align 'C'
Background lightgray
Foreground darkgray
}

Widget SetSyslogMsg {
class 'Timer'
expression SyslogMsg = exec('tail -n 1 /var/log/syslog', 2 * second)
active 1
update 2 * second
}

Widget Syslog1 {
class 'Text'
expression substr(SyslogMsg, 0 * width100, width100)
width width100
align 'L'
Background darkgray
update 2 * second
}

Widget Syslog2 {
class 'Text'
expression substr(SyslogMsg, 1 * width100, width100)
width width100
align 'L'
Background darkgray
update 2 * second
}

Widget Syslog3 {
class 'Text'
expression substr(SyslogMsg, 2 * width100, width100)
width width100
align 'L'
Background darkgray
update 2 * second
}

Widget Syslog4 {
class 'Text'
expression substr(SyslogMsg, 3 * width100, width100)
width width100
align 'L'
Background darkgray
update 2 * second
}

Widget Debug {
class 'Text'
# expression cfg('Layout')
expression '$Revision: 1.25 $ -- DPF Driver by hackfin'
width linesize
align 'C'
Foreground lightgray
}

Widget na {
class 'Text'
expression 'n/a'
width 3
align 'L'
}

Widget Bgnd {
class 'Image'
file '/usr/local/share/backgrounds/mythbuntu-320x240.png'
reload 0
update 0
inverted 0
visible 1
}

Widget BgndDS {
class 'Image'
file '/usr/local/share/backgrounds/dockstar-320x240.png'
reload 0
update 0
inverted 0
visible 1
}

Layout Ubuntu {
Row01.Col01 'System'
Row02.Col01 'Time'
Row04.Col02 'Busy'
Row05.Col02 'BusyBar'
Row07.Col02 'Load'
Row08.Col02 'LoadBar'
Row10.Col02 'Disk'
Row11.Col02 'DiskBar'
Row13.Col02 'Eth0'
Row14.Col02 'Eth0Bar'
Row16.Col02 'DVB'
Row17.Col02 'DVBBar'

Row04.Col28 'MemoryTitle'
Row05.Col29 'MemoryTotal'
Row06.Col29 'MemoryFree'
Row07.Col29 'MemorySwapped'
Row09.Col28 'HDDTempTitle'
Row10.Col29 'HDDTemp1'
Row10.Col35 'HDDTemp2'
Row10.Col41 'HDDTemp3'
Row12.Col28 'FSSpaceTitle'
Row13.Col29 'FSSpace1'
Row14.Col29 'FSSPace2'
Row15.Col29 'FSSpace3'
Row16.Col29 'FSSpace4'
Row17.Col29 'FSSpace5'

Row19.Col02 'ServicesTitle'
Row20.Col02 'ApacheStatus'
Row21.Col02 'MySQLStatus'
Row22.Col02 'MythTVStatus'
Row23.Col02 'PostfixStatus'
Row20.Col29 'SambaStatus'
Row21.Col29 'SSHStatus'
Row22.Col29 'SWRAIDStatus'
Row23.Col29 'TwonkyStatus'

Row25.Col02 'SyslogTitle'
Row26.Col02 'Syslog1'
Row27.Col02 'Syslog2'
Row28.Col02 'Syslog3'
Row29.Col02 'Syslog4'

Row30.Col01 'Debug'

Timer1 'SetSyslogMsg'

# Layer 2 {
# X1.Y1 'Bgnd'
# }

}

Layout Dockstar {
Row01.Col01 'System'
Row02.Col01 'Time'
Row04.Col02 'Busy'
Row05.Col02 'BusyBar'
Row07.Col02 'Load'
Row08.Col02 'LoadBar'
Row10.Col02 'Disk'
Row11.Col02 'DiskBar'
Row13.Col02 'Eth0'
Row14.Col02 'Eth0Bar'

Row04.Col28 'MemoryTitle'
Row05.Col29 'MemoryTotal'
Row06.Col29 'MemoryFree'
Row07.Col29 'MemorySwapped'
Row09.Col28 'HDDTempTitle'
Row10.Col29 'na'
Row12.Col28 'FSSpaceTitle'
Row13.Col29 'FSSpace1'
# Row14.Col29 'FSSpace2'
Row14.Col29 'FSSpace4'
Row15.Col29 'FSSPace5'

Row16.Col02 'ServicesTitle'
Row17.Col02 'PortmapStatus'
Row18.Col02 'SSHdStatus'
Row19.Col02 'RsyslogStatus'
Row20.Col02 'NFSdStatus'
Row21.Col02 'pyloadStatus'
# Row22.Col02 'PostfixStatus'
# Row23.Col02 'ProFTPStatus'
# Row17.Col29 'SambaStatusDS'
# Row18.Col29 'SSHStatusDS'

Row23.Col02 'SyslogTitle'
Row24.Col02 'Syslog1'
Row25.Col02 'Syslog2'
Row26.Col02 'Syslog3'
Row27.Col02 'Syslog4'

Row30.Col01 'Debug'

Timer1 'SetSyslogMsg'

# Layer 2 {
# X1.Y1 'BgndDS'
# }

}

VirtualBox USB in guest

To add a USB device connected to the host to the guest, I found the following procedure beneficial:

  • start VirtualBox
  • open USB connection setup page
  • connect USB device
  • add filter for newly connected USB device in VBox setup
  • if necessary eject device from host (diskutil eject /dev/disk?)
  • start guest and see if connection was successful
  • reconnect if necessary

snmp v3

to get the net-snmp-config tool the libsnmp-dev package must be installed:

# apt-get install libsnmp-dev
# net-snmp-config –create-snmpv3-user -ro -A ‘geheim’ -X ‘secret’ -a SHA -x AES icinga

you may also create a new user using snmp commands:

#snmpusm -v 3 -u -l authNoPriv -a MD5 -A localhost passwd

to simplify the usage a local user profile should be created in ~/.snmp/snmp.conf:

defSecurityName
defContext “”
defAuthType MD5
defSecurityLevel authNoPriv
defAuthPassphrase defVersion 3

now a simple command looks like:

#snmpget localhost sysUpTime.0

Mirror – semi-transparent mirror info panel

I recently started building my own version of a semi-transparent mirror info panel. The server inside is running as a main service station for basically everything.
The server is hosting an external hard disk to serve videos, music and hard disk space via minidlna, nfs, appletalk and samba. Further the server is hosting my mail, imap, icinga, etc services.

A web front end is showing the basic information on an LCD behind the semi-transparent screen and here comes the PHP behind:

<?php ############# HEAD  ############################
$refresh_period = "3600";# refresh once in an hour only
$PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); # use one file only which will be reload with new parameters all the time
header("Refresh: $refresh_period; url=$PHP_SELF");
echo "<!DOCTYPE html>\n";
echo "<html>\n<head>\n <meta http-equiv='refresh' content='.".$refresh_period."'><meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'>\n";
require_once('simpleCalDAV/SimpleCalDAVClient.php');
$client = new SimpleCalDAVClient();
$zeiger = array("Stunde", "Minute", "Sekunde");
############# Configuration ##########################
$numberClocks = array("Shenzen" => 2, "Saarbruecken" => 0);
$calendar_config = array('server' => '<server adress>/remote.php/dav/calendars/olkn/personal/', 
						'login' => '<login>', 
						'password' => '<password>',
						'calendar' => 'personal');
$tokens = array('SUMMA', 'DESCR', 'DTSTA', 'LOCAT', 'DTEND');// tokens to check for in calendar entry
############# style sheets ########################
echo "<link rel='stylesheet' type='text/css' href='stylesheet.css'>\n";
echo "<style>\n";
foreach ($numberClocks as $ort => $zeitzone){
	$rotation["Stunde"] = (date("h") + $zeitzone) * 30 + round(date("i")/2);# define hour rotation including timezone and minute part
	$rotation["Minute"] = date("i") * 6;# define minute rotation and
	$rotation["Sekunde"] = date("s") * 6;# second rotation
	foreach ($zeiger as $zeigername){
		$rotstart = $rotation[$zeigername];$rotstop = $rotation[$zeigername]+360;
		$temp = $zeigername.$ort;# CSS class name is StundeShenzen, etc
		echo ".".$temp." { \n\t-moz-animation-name: drehen".$temp.";\n\t-webkit-animation-name: drehen".$temp." ;\n\t";
		echo "-o-animation-name: drehen".$temp.";\n\t-ms-animation-name: drehen".$temp.";\n\tanimation-name: drehen".$temp.";\n\t";
		echo "-moz-animation-iteration-count: infinite;\n\t-webkit-animation-iteration-count: infinite;\n\t";
		echo "-o-animation-iteration-count: infinite;\n\t-ms-animation-iteration-count: infinite;\n\t";
		echo "animation-iteration-count: infinite;\n\t-moz-animation-direction: normal;\n\t-webkit-animation-direction: normal;\n\t";
		echo "-o-animation-direction: normal;\n\t-ms-animation-direction: normal;\n\tanimation-direction: normal;\n\t";
		if ($zeigername == "Sekunde"){# second hand will go in steps rather than continously
			echo "-moz-animation-timing-function: steps(60);\n\t-webkit-animation-timing-function: steps(60);\n\t";
			echo "-o-animation-timing-function: steps(60);\n\t-ms-animation-timing-function: steps(60);\n\tanimation-timing-function: steps(60);\n\t}\n";
		} else {
			echo "-moz-animation-timing-function: linear;\n\t-webkit-animation-timing-function: linear;\n\t";
			echo "-o-animation-timing-function: linear;\n\t-ms-animation-timing-function: linear;\n\tanimation-timing-function: linear;\n\t}\n";
		}
		echo "@-moz-keyframes drehen".$temp." { \n\tfrom { -moz-transform: rotate(".$rotstart."deg); } \n\tto { -moz-transform: rotate(".$rotstop."deg); } \n}\n";
		echo "@-webkit-keyframes drehen".$temp." { \n\tfrom { -moz-transform: rotate(".$rotstart."deg); } \n\tto { -moz-transform: rotate(".$rotstop."deg); } \n}\n";
		echo "@-o-keyframes drehen".$temp." { \n\tfrom { -moz-transform: rotate(".$rotstart."deg); } \n\tto { -moz-transform: rotate(".$rotstop."deg); } \n}\n";
		echo "@-ms-keyframes drehen".$temp." { \n\tfrom { -moz-transform: rotate(".$rotstart."deg); } \n\tto { -moz-transform: rotate(".$rotstop."deg); } \n}\n";
		echo "@keyframes drehen".$temp." { \n\tfrom { -moz-transform: rotate(".$rotstart."deg); } \n\tto { -moz-transform: rotate(".$rotstop."deg); } \n}\n";
	}
}
echo "</style>\n";
echo "<title>Mirror</title>\n</head>\n<body>\n\n";
############################## MAIN ##################################
date_default_timezone_set('Europe/Berlin');# set time zone
############## show weather on top right #############################
echo "<a href='second.php'><div class='header'>\n";
echo "<div id='cont_29118c24cbd1fe3b37edea315a92451d'><span id='h_29118c24cbd1fe3b37edea315a92451d'>";
echo "</span><script type='text/javascript' async src='https://www.daswetter.com/wid_loader/29118c24cbd1fe3b37edea315a92451d'>";
echo "</script></div>";
echo "</div>\n";# header
############### show calender and clock on bottom ####################
echo "<div class='footer'>\n";
echo "<div class='calendar'>\n";
try {
	$client->connect($calendar_config['server'], $calendar_config['login'], $calendar_config['password']);
	$arrayOfCalendars = $client->findCalendars();# get all available calendars
	$client->setCalendar($arrayOfCalendars[$calendar_config['calendar']]);# choose specific calendar
	$events = $client->getEvents(date('Ymd')."T000000Z", date('Ymd')."T240000Z"); # get list of events for today
	echo "<div class='calendar_header'>".date("l d.F Y")."</div>\n";# show current date
	foreach ($events as $event){
		$results = array();
		$event_data = explode("\n", $event->getData());
		foreach ($event_data as $line){
			list($key, $value) = explode(":", $line);
			if ($key == "BEGIN" && $value == "VEVENT") $trigger = true;// only check VEVENT entries
			elseif ($key == "END") $trigger = false;// other entries will be ignored
			if ($trigger){
				$key = substr($key, 0, 5);// DTSTART and END use complexe format, so the beginning of the word is enough
				if (in_array($key, $tokens)){// we found a relevant token, so store it in array for this event
					$results[$key] = $value;
				}
			}//end of triggering
		}//mext line of ICALENDAR Event
		echo "<div class='calendar_contents'>\n";
		if (strstr($results['DTSTA'], 'T') && strstr($results['DTEND'], 'T')){//we have a specific time (no whole day entry)
			echo "<div class='calendar_time'>".str_split(substr($results['DTSTA'], -6), 2)[0].":".str_split(substr($results['DTSTA'], -6), 2)[1];
			echo " - ".str_split(substr($results['DTEND'], -6), 2)[0].":".str_split(substr($results['DTEND'], -6), 2)[1];
			echo "</div>\n";//calendar_time
		}//event time processing
		echo $results['SUMMA']."\n<div class='calendar_entry'>".$results['DESCR']."</div>\n";//calendar_entry
		if (isset($results['LOCAT'])) echo "<div class='calendar_location'>".$results['LOCAT']."</div>\n";//calendar_location
		echo "</div>\n";//calender_contents
	}// next event
}
catch (Exception $e) {
	echo $e->__toString();
	echo "Error during catching calendar entries from Server<br>";
}
echo "</div>\n";# calender
############### show two clocks for worldtime ########################
echo "<div class='clock'>\n";
foreach ($numberClocks as $ort => $zeitzone){
	echo "<div class='clock_inner'>\n";
	echo "\t<div class='uhr'>\n";
	echo "\t<ul class='markierungen'>\n<li id='mark01'><div></div></li><li id='mark02'><div></div></li>\n";
	echo "\t<li id='mark03'><div></div></li><li id='mark04'><div></div></li>\n<li id='mark05'><div></div></li>";
	echo "\t<li id='mark06'><div></div></li>\n<li id='mark07'><div></div></li><li id='mark08'><div></div></li>\n";
	echo "\t<li id='mark09'><div></div></li><li id='mark10'><div></div></li>\n<li id='mark11'><div></div></li>";
	echo "\t<li id='mark12'><div></div></li>\n</ul>\n";
	foreach ($zeiger as $zeigername){
		echo "\t<div class='".$zeigername.$ort."' id='".$zeigername."'></div>";
	}
	echo "\t</div><div class='clock_location'>".$ort."</div>\n";
	echo "</div>\n";# clock_inner
}
echo "</div>\n";# clock
echo "</div>\n</a>";# footer
############### close ####################################################
echo "</body>\n</HTML>\n";
########### END ###################################?>

There is also a second page, which is showing some statistics about the server:

<?php ############# HEAD  ############################
echo "<!DOCTYPE html>\n";
echo "<html>\n<head>\n <meta charset='utf-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'>\n";
############# style sheets ########################
echo "<link rel='stylesheet' type='text/css' href='stylesheet.css'>";
echo "<title>Mirror</title>\n</head>\n<body>\n\n";
############# Configuration ##########################
$PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); # use one file only which will be reload with new parameters all the time
$display_size = array(1024, 768);
###### debug output of POST
function debug_output(){
        echo "<pre><br><h1>Hier kommt der schamass!</h1>";
        print_r($_POST);
        echo "</pre>"; return ;
}
######################################################################
############################## MAIN ##################################
######################################################################
echo "<body><form method='POST' action='$PHP_SELF'>\n";# page header with headline and table headers
echo "<a href='index.php'><section class='contents'>";
############## show weather on top right #############################
echo "<table width='100%' border=1><tr>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=12&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=24&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "</tr><tr>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=20&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=38&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "</tr><tr>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=40&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=9&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "</tr><tr>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=23&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "<td><img src='<cacti-server-adress>/graph_image.php?local_graph_id=9&rra_id=1&graph_width=500&graph_height=120&graph_nolegend=true'></td>";
echo "</tr></table>";
echo "Nagios Entries!";
echo "</section>";
############# cleanup and end ########################################
#debug_output();
echo "</form>\n<footer id='footer'>My personal page hosted on my own server &copy; olkn</footer></a></body></HTML>\n";
########### END ###################################?>