Category Archives: Linux/BSD

Corda Node Migration

Es gibt leider nicht viele Information wenn man einen Corda node auf einen neuen Server migrieren muss. Was man unbedingt braucht ist ein Backup der Datenbank, der Keys – am besten vom ganzen Corda Verzeichnis das alle kritischen Daten enthält (wie auch die Cordaaps).

Was man jedoch nicht braucht ist die nodekeystore.jks. Die wird basierend auf dem Hostnamen (vermutlich) erstellt und muss auf dem neuen System neu erstellt werden. Das passiert automatisch beim starten von Corda. Falls man die Datei nicht löscht wird der Node nicht erkannt und wird von der Map immer wieder gelöscht.

network.PersistentNetworkMapCache. - Removing node with info: NodeInfo(addresses=[xxx.xxx.xxx.x:10002], 

Grafana Image Renderer Konfiguration

Seit Grafana 7.x benutzt Grafana ein grafana-image-renderer oder man benutzt einen docker container dafuer. Ich habe mich für das Plugin entschieden, aber vielleicht wäre der Container einfacher gewesen. Auf Debian 10 braucht das Plugin doch ein paar Abhängigkeiten die nirgendswo zu finden sind.

Installation des Plugins:

grafana-cli plugins install grafana-image-renderer

Installation Abhaengigkeiten:

apt install cups fonts-liberation gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget

Wenn man Grafana mit TLS konfiguriert hat muss man entweder den host korrekt setzen, ansonsten bekommt man eine Fehlermeldung weil Grafana versucht nach localhost:3000 zu verbinden.

Error:

grafana-server[25147]: 2020/12/18 07:18:47 http: TLS handshake error from [::1]:55768: remote error: tls: unknown certificate
grafana-server[25147]: t=2020-12-18T07:18:47+0000 lvl=eror msg="Browser request failed" logger=plugins.backend pluginId=grafana-image-renderer method=GET failure=net::ERR_CERT_COMMON_NAME_INVALID url="https://localhost:3000/d-solo/iuCnU9JGz/test?orgId=1&panelId=2&render=1"
grafana-server[25147]: t=2020-12-18T07:18:47+0000 lvl=eror msg="Render request failed" logger=plugins.backend pluginId=grafana-image-renderer url="https://localhost:3000/d-solo/iuCnU9JGz/test?orgId=1&panelId=2&render=1" error="Error: net::ERR_CERT_COMMON_NAME_INVALID at https://localhost:3000/d-solo/iuCnU9JGz/test?orgId=1&panelId=2&render=1"grafana-server[25147]: t=2020-12-18T07:18:47+0000 lvl=eror msg="Failed to render and upload alert panel image." logger=alerting.notifier ruleId=2574 error="Rendering failed: Error: net::ERR_CERT_COMMON_NAME_INVALID at https://localhost:3000/d-solo/iuCnU9JGz/test?orgId=1&panelId=2&render=1"

Konfiguration in /etc/grafana/grafana.ini

[plugin.grafana-image-renderer]
rendering_ignore_https_errors = true

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)

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.