Confluence H2DB korrupiert

Confluence benutzt normalerweise H2DB, eine file based Datenbank. Sollte man nicht in Produktion benutzen, aber so ist das manchmal im Leben. Wenn dann auch noch der Server oder ein filesystem problem auftaucht kann es zu einer korrupten Datenbank kommen. Confluence selber bietet keine tools an um die Datenbank zu reparieren, aber ein findiger Benutzer hat ein gutes tool geschrieben um dieses durchzuführen.

Der Fehler von Confluence:

Cannot connect to h2db
java.lang.RuntimeException: Cannot connect to h2db

Undo MVStore log:

sudo apt install maven
git clone https://github.com/bert2002/h2-recover.git
cd h2-recover
mvn clean package
java -jar target/h2-recover-1.0-SNAPSHOT.jar /path/to/h2.mv.db

Der Standardpfad bei Confluence der Datenbank is in /var/atlassian/application-data/confluence/database/. Vorher nicht vergessen ein Backup zu erstellen.

Docker load vs import

Nachdem man einen Docker container exportiert hat kann man diesen mit docker import oder docker load importieren. Jedoch funktioniert nur docker load correct und import führt zu einem irritierenden Fehler:

$ docker import tools-1597033145.tar.gz tools:latest
sha256:f229b184eb2f0c0f2c59fac86adec2c32ac742a8fc1ea6898f51543dfbf0161b
$ docker run -it tools /bin/bash
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"/bin/bash\": stat /bin/bash: no such file or directory": unknown.
ERRO[0003] error waiting for container: context canceled

Wenn man den Container mit load importiert, funktioniert es einwandfrei. Ich hatte leider noch keine Zeit den unterschied oder Fehler zu untersuchen, aber es hat etwas mit export/import und save/load zu tun. Export erstellt snapshots und save erstellt einen dump.

Reverse SSH Tunnel mit Autossh

Einen SSH Tunnel kann man für viele nützliche Sachen einsetzen und hilft bei authentification und verification von einer Verbindung.

Im Normalfall verbindet man Server1 mit Server2 und jetzt ist es möglich von Server1 nach Server2 den Tunnel zu benutzen.
Ich hatte jetzt das Problem dass die IP von Server2 sich immer veraendert und es keinen offenen Port auf Server2 gibt. Ich musste jedoch von Server1 auf Server2 zugreifen. Dabei hilft uns ein reverse SSH Tunnel. Der Tunnel wird von Server2 aufgebaut nach Server1, aber ich kann von Server1 auf den Tunnel zugreifen.

Das ist schnell und einfach konfiguriert und ist eine einfach systemd konfiguration nachdem man autossh installiert hat.

Datei: /etc/systemd/system/autossh.service

[Unit]
Description=Opens a ssh tunnel and keeps it open
After=network-online.target

[Service]
# AUTOSSH_GATETIME is used to restart ssh within autossh when a connection failed.
Environment=AUTOSSH_GATETIME=0
User=root
ExecStart=/usr/bin/autossh -N -q -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -p 22 -l $USERNAME -R $REMOTEPORT:localhost:22 $REMOTEHOST

[Install]
WantedBy=multi-user.target

$USERNAME: Der Benutzername mit dem man sich auf Server1 verbinden möchte.
$REMOTEPORT: Der Port auf dem der Tunnel auf Server1 lauschen soll
$REMOTEHOST: Die Adresse von Server1

Am besten tested man die Verbindung manuell einmal, damit man auch den Hostkey verifiziert (ssh pubkey muss vorher ausgetauscht werden) wird, ansonsten kann man den Dienst aktivieren.

systemctl daemon-reload
systemctl start autossh

Gitlab Projects import nach Searchcode

Die Codesuche in Gitlab selber ist etwas beschraenkt und man muss auf Drittanbieter zurueckgreifen. Ich teste momentan Searchcode. Die Community version is kostenlos und fuer etwas Geld bekommt man mehr funktionen.
Das Problem ist jedoch das man jedes git repository einzeln hinzufuegen muss. Zum Glueck gibt es eine API die das einem abnehmen kann. Dabei exportieren wir die List aus Gitlab und importieren diese automatisch nach Searchcode.

Zum Glueck kann man mit ssh keys arbeiten, jedoch muss man dafuer die Config anpassen.

Datei: ~/.ssh/config

Host gitlab.example.com
	IdentityFile ~/.ssh/id_rsa
	StrictHostKeyChecking no

Anschliessen muss man folgendes Script anpassen und auf dem Server wo Searchcode laeuft ausfuehren.

#!/usr/bin/python
# script: import gitlab projects into searchcode
# author: bert2002
# notes: 

import sys
import os
import json
import urllib2
from hashlib import sha1
from hmac import new as hmac
import urllib2
import json
import urllib
import pprint
import time

# Gitlab Settings
TOKEN = 'SECRET_ACCESS_TOKEN'
GITLAB = 'https://gitlab.example.com/api/v4/'

# Searchcode Settings
publickey = "SECRET_PUBLICKEY"
privatekey = "SECRET_PRIVATEKEY"

print "checking jobs in gitlab"
req = urllib2.Request(GITLAB + 'projects?page=1&per_page=100')
req.add_header('Content-Type', 'application/json')
req.add_header('PRIVATE-TOKEN', TOKEN)
data = json.load(urllib2.urlopen(req))

for project in data:
  job_id = project['id']
  ssh_url_to_repo = project['ssh_url_to_repo']
  name_with_namespace = project['name_with_namespace']
  path_with_namespace = project['path_with_namespace']
  web_url = project['web_url']
  archived = project['archived']

  print("Repository: %s Archived: %s" % (name_with_namespace,archived))

  reponame = name_with_namespace
  repourl = ssh_url_to_repo
  repotype = "git"
  repousername = ""
  repopassword = ""
  reposource = web_url
  repobranch = "master"

  message = "pub=%s&reponame=%s&repourl=%s&repotype=%s&repousername=%s&repopassword=%s&reposource=%s&repobranch=%s" % (
          urllib.quote_plus(publickey),
          urllib.quote_plus(reponame),
          urllib.quote_plus(repourl),
          urllib.quote_plus(repotype),
          urllib.quote_plus(repousername),
          urllib.quote_plus(repopassword),
          urllib.quote_plus(reposource),
          urllib.quote_plus(repobranch)
      )

  sig = hmac(privatekey, message, sha1).hexdigest()
  url = "http://localhost:8080/api/repo/add/?sig=%s&%s" % (urllib.quote_plus(sig), message)
  data = urllib2.urlopen(url)
  data = data.read()
  data = json.loads(data)
  print data['sucessful'], data['message']

  sig = hmac(privatekey, message, sha1).hexdigest()
  url = "http://localhost:8080/api/repo/reindex/?sig=%s&%s" % (urllib.quote_plus(sig), message)
  data = urllib2.urlopen(url)
  data = data.read()
  time.sleep(1)

ESP8266 + OLED Display shows PagerDuty incidents

Seit ein paar Tagen spiele ich mit dem ESP8266 Chip herum. Das ist ein Arduino fähiger Chip mit Wifi. Die Entwicklerboards gibt es schon für knapp 8EUR in Deutschland und sind überraschend leistungsfähig. 
Ich hatte vorher noch nie etwas mit Arduino gemacht, aber dank der vielen verfügbaren Libraries hat man sehr schnell Erfolg mit kleinen Projekten. So habe ich noch ein kleines Display angeschlossen und dieses zeigt mir die offenen incidents bei PagerDuty an. Super schnell und lustig. 

Den Code gibt es auf github.com und hier ein Beispiel:

ESP8266 + Arduino IDE + MacOSX

Das Internet of Things (IoT) immer mehr in unseren Alltag Einfluss nimmt, ist vermutlich jedem klar. Ich wollte auch ein bisschen damit herumspielen und bin dabei auf den Chip ESP8266 gestoßen. Der kleine Chip hat WLAN, verbraucht wenig Strom und kann mittels LUA oder Arduino IDE programmiert werden.

Unter Linux ging das alles sehr schnell und nachdem man die Arduine IDE und das Board Packet installiert hat, kann man direkt loslegen. Unter MacOSX Sierra hatte ich jedoch Probleme dass das Board in der Arduino IDE erkannt wird. Erst nach langem recherchieren bin ich auf einen Treiber gestoßen der funktioniert. 

Den Treiber und mehr gibt es auf kig.re.

Monero Mining on Ubuntu 16.04

Account:

Der einfachste Weg einen Account zu erstellen ist auf mymonero.com. Man muss sich um keine Blockchain kümmern und es ist komplett Anonym. Auf der Seite bekommt man auch seine WalletID die wir bei dem Miner mit angeben müssen. Diese müsst Ihr bei $WALLETID ersetzen. Als Mining Pool nehmen wir monerohash.com

Installation:

apt update
apt install libcurl4-openssl-dev libncurses5-dev pkg-config automake yasm
sysctl -w vm.nr_hugepages=48 # three times more then your cpu cores
cd /opt/
git clone https://github.com/wolf9466/cpuminer-multi
cd cpuminer-multi
./autogen.sh
CFLAGS="-march=native" ./configure
make

Start:

/opt/cpuminer-multi/minerd -a cryptonight -o stratum+tcp://monerohash.com:3333/
-u $WALLETID -p $RANDOM

Reporting:

Falls man mehrere Instanzen am laufen hat, will man diese auch ein bisschen überwachen bzw. wissen was läuft. Dafür habe ich einen kleinen Bot geschrieben der mit der Monerohash IP sich die aktuellen Daten zieht und diese mir in einem Slack Channel sendet. Das ganze gibt es auf github.com.

BlaBlaDNS – Ein Kostenloser DynDNS Anbieter

NOTE: BlaBlaDNS ist jetzt bekannt als TokenDNS.

Ich darf mit Freude verkünden das endlich mein neustes Projekt online gegangen ist. Ein kleiner, aber feiner Dynamic DNS Dienst der natürlich kostenlos ist. Getauft ist das Projekt auf BlaBlaDNS und kann unter www.blabladns.co erreicht werden.

Es gibt schon unzählige DDNS Dienste, aber leider keiner der mir alle Features bot die ich haben wollte. Er sollte sicher sein, schöne API und ich wollte auch IPv6 Rekords sowie die TTL bestimmen können. Konnte ich nicht finden und so musste ich mir einen bauen.
Momentan muss man die API unbedingt benutzen, weil das Webinterface noch keinen Schreibzugriff auf die API hat, aber das wird sich bald ändern.

Wie kann ich also BlaBlaDNS benutzen?

Als erstes muss man sich sicher anmelden und wenn man den API Key hat kann man direkt los legen. Den rest kann man einfach per API machen. Beispiele existieren momentan für curl, aber die Dokumentation wird noch erweitert.

Kleines Beispiel um die Subdomain www5.blabladns.xyz zu registrieren und aktualisieren.

Subdomain Registrieren

curl --get "https://api.blabladns.co/v1/reserve" \
  -d apikey=${apikey} \
  -d name=www5

Rekord Aktualisieren

curl --get "https://api.blabladns.co/v1/update" \
  -d apikey=${apikey} \
  -d name=www5 \
  -d content=$(curl -4 ifconfig.co)

Status

curl --get "https://api.blabladns.co/v1/reserve" \
  -d apikey=${apikey} \
  -d name=www5

Rekord automatisch mit cron aktualisieren

echo "0 * * * * root curl -s --get https://api.blabladns.co/v1/update -d apikey=${apikey} -d name=www5 -d content=$(curl -s -4 ifconfig.co) >/dev/null" > /etc/cron.d/blabladns

Die Features und Möglichkeiten werden in nächster Zeit noch weiter wachsen und wer die Entwicklung weiter verfolgen möchte sollte dem Blog von BlaBlaDNS folgen.
Wünsche? Anregungen? Features? Gerne baue ich die in den Dienst ein! Einfach Melden!

Chef + Ruby Integration

Auch wenn Chef Ruby einsetzt unterstützt es leider doch nicht alles. Ich wollte eine nette Regex direkt im Cookbook ausführen lassen. In Ruby wunderbar funktioniert, beim Chef run wurde die Regex nicht korrekt ausgeführt. Ich habe sogar zwei verschiedene ausprobiert (wobei die erste nicht ganz korrekt ist, aber auch funktioniert), aber leider Erfolglos. sed funktioniert eben einfach immer :)

Regex: Kommentiere eine Zeile, wenn ubuntu.com oder canonical.com enthalten ist und nicht mit einer Raute anfängt.

 ruby_block 'modify /etc/apt/sources.list' do
  block do
    File.write( f = "/etc/apt/sources.list",
      #File.read(f).gsub(/(?!^#)(.*)(?:ubuntu\.com|canonical\.com)(.*)/) { "# #{$&}" }
      File.read(f).gsub(/^[^!#]*(?:ubuntu\.com|canonical\.com)/m) { "# #{$&}" }
    )
  end
end
 

Lösung:

execute 'modify /etc/apt/sources.list with sed' do
  command "sed -i -e '/ubuntu\.com/s/^#*/#/' -e '/canonical\.com/s/^#*/#/' /etc/apt/sources.list"
end

Cloudera Manager und Grafana

example_graph

In dem Cloudera Manager kann man sich schon verschiedene Grafen der einzelnen Komponenten anschauen, wenn man jedoch auch Grafana benutzt will man nicht wirklich immer umschalten.
Es ist jedoch möglich ein Plugin für Grafana zu schreiben um die Daten direkt aus dem CDH zu ziehen. Amir Pakdel hatte ein Plugin für Grafana 1.x geschrieben, welches ich für Grafana 2.x umgeschrieben habe.

Download: Grafana CDH Datasource Plugin

Installation

Damit wir in kein Problem mit XSS kommen müssen wir unsere anfragen an das CDH mit einem kleinen Proxy über den Server von Grafana abfertigen. Dafür muss folgende Apache Konfiguration angelegt werden:


    ProxyPass http://$CLOUDERAMANAGER:7180/api/v9
    ProxyPassReverse http://$CLOUDERAMANAGER:7180/api/v9
    RequestHeader set Authorization "Basic <base64>"
    Header set Access-Control-Allow-Origin "*"

Das $CLOUDERAMANAGER muss mit dem Hostnamen von dem CDH Manager ersetzt werden und in dem RequestHeader der Benutzername:Passwort (in base64) von dem Benutzer der mit der API von CDH reden darf. Anschließend noch ein paar Module aktivieren:

# a2enconf cdh
# a2enmod proxy_http proxy request headers
# service apache2 restart

Anschließend können wir das Modul installieren und Grafana neu starten. Vor dem Neustart, muss jedoch noch die $GRAFANAURL in der datasource.js angepasst werden.

 # tar -xzf cdh.tar.gz -C /usr/share/grafana/public/app/plugins/datasource/ 
# service grafana-server restart

Jetzt kann man schon beginnen eine neue Datasource zu erstellen und fleißig Graphen bauen. Wie baut man die Graphen? Man muss die SQL Statements aus dem CDH in Grafana übertragen. Die Statements bekommt man aus den vorhanden Graphen:

hdfsio

In dem JSON befindet sich das Query, welches einfach in die Row im Grafana eingetragen werden muss. Fertig.

Owncloud 8.0 Upgrade

Wenn man momentan auf Owncloud 8.0 upgraded erhalten viele Benutzer nur noch eine weiße Seite und nichts passiert. In den Logdateien kann man auch keine Fehler finden.
Das Problem liegt an ein paar Plugins die noch nicht für 8.0 aktualisiert worden. Diese muss man deaktivieren:

# cd /zur/deiner/owncloud
# sudo -u www-data php occ app:disable calendar
# sudo -u www-data php occ app:disable contacts