tldr: Avira face punches VirtualBox. Need other virus scanner.
I was using Avira, because it is the best free virus scanner. And I am using VirtualBox for sandboxed Windows, local Linuxes, as docker container host, etc...
...but recently they stopped working together.
Over 2 weeks VirtualBox VMs were increasingly less likely to start. I needed some time and googling to find out that Avira prevents the VM from starting. Disable Avira: still nogo. Uninstall Avira: VirtualBox works. Reinstall Avira: VirtualBox broken again.
See: https://forums.virtualbox.org/viewtopic.php?f=6&t=68869
Time to move on to a different virus scanner.
_happy_googling()
7. Dezember 2015
Avira and VirtualBox Broken
6. Dezember 2015
Life is Strange
Habe in den letzten Tagen Life is Strange als Letsplay geschaut. Gefällt mir super. Ist wie Fernsehen. So soll es sein. Zurücklehnen vorspielen lassen.
Es spielt sich fast von selbst. Ab und zu mal was suchen, kleine Aufgaben lösen. Nichts wo ich nicht weiterkomme. Genau mein Schwierigkeitsgrad.
Nie wieder Open World. Spielen auf Schienen. Keine schwierigen Aufgaben zu lösen, Keine Leute umzubringen, keine NPCs, die warten bis sie gemetzelt werden. Ich kann die meisten Entscheidungen revidieren. Manche aber nicht. Das Spiel führt mich in der Story weiter. Interaktives Kino mit starken Emotion und Chillfaktor.
Gibt's für PS3. PS3 habe ich seit Assassin's Creed III. Das war das einzige Spiel was ich auf der PS3 gespielt habe (und das nur halb). Also kann ich mit Life is Strange meine Investition von 400 € pro Game auf 200 € pro Game verringern. Reichgespart.
_happy_chilling()
PS: Das Game auf die PS3 zu bringen war auch schon eine Quest-Reihe. Ich sach nur Controller aktivieren, System Update, zu alter Account, problematische Payment-Optionen, mehr Updates, Downloads, mehr Downloads, Updates, Shop verlassen, wieder rein, Reboot, Update, immer wieder Auflösung Umschalten und dann viele Screens (Engine, Publisher, Developer, alle toll) bis das Game endlich startet. Unchillig das.
23. Oktober 2015
Galactic Developments ist umgezogen auf einen neuen Server als KVM
Bisher war die Galactic Developments Website ein Apache Virtual Server auf meinem alten Hetzner Rootserver. Den hatte ich vor 6 Jahren bei einer keine-Setupgebühr-Aktion gebucht (und dann 3 Monate lang nicht installiert, was die keine-Setupgebühr-Aktion für mich ad-absurdum geführt hat, für Hetzner nicht). Inzwischen ist das Betriebssystem (Debian Sarge) aber schon aus den Security-Fixes raus gelaufen.
Die Rechner der Rabatt-Aktion waren damals etwas schwach auf der Brust. Das stört nicht, wenn man nicht viel Traffic hat, aber heutzutage will man virtualisieren und mehrere Server gleichzeitig laufen lassen. Dafür ist ein ganzes GB RAM nicht genug. Der neue Server ist wieder bei Hetzner, hat aber 2 TB Platte, 32 GB RAM, 8 CPUs incl. Hyperthreading. Das sollte reichen für ein paar virtuelle.
Ich kann Debian, also weiter Debian-stable, d.h. Jessie 8.2.
Zum Virtualisieren kvm und libvirt drauf. Ein 2 GB Image für das Guest-Template erstellen mit einer Debian-minimal Installation ohne alles außer sshd. Die VMs sind nur über das interne "default" Netzwerk zu erreichen. Alle VMs bekommen statische IP Adressen vom internen DHCP.
Ein VM als Reverse-Proxy, der HTTP-Requests an verschiedene virtuelle Maschinen weiterleitet. Dafür eine iptables-Konfiguration per qemu-Hook, die immer dann die 2 iptables-Regeln setzt/löscht, wenn die VM startet/stoppt. Auf dem Proxy ein nginx, der alle Anfragen für www.galactic-developments.de an die Galactic Developments VM weiterleitet.
Der Galactic Developments Server bekommt eine eigene VM. Hier mit Apache, weil ich Apache schon kann und nicht zu viele Konfiguration ändern muss, dachte ich. Tatsächlich haben sich die Apache Entwickler ein neues Sicherheitskonzept einfallen lassen und erst mal geht gar nichts, bis ich herausfinde, dass man einen neuen Befehl (Require) braucht. Zusätzlich zum Galactic Developments Apache virtual Server gibt es noch einen CatchAll virtual Server, der Adressen wie galactic-developments.de (ohne www.) und *.galactic-developments.com auf den Hauptserver umleitet (401/permanent).
Dateien und Daten der Galactic Developments Website sind in Subversion. Das bleibt erstmal so bis sich die Community mehr beteiligt. Dann will ich git nicht im Wege stehen. Also: Repository auschecken und Apache-config darauf zeigen lassen. Bisher waren SVN Server und Website auf dem gleichen Rechner. Ein Subversion post-commit Hook hat automatisch die Website svn update'd. Poor man's Continuous Delivery. Das geht jetzt nicht mehr, weil es verschiedene Rechner sind und später - wenn der SVN Server auch umgezogen ist - gleicher Rechner, aber getrente VMs. Deshalb muss der post-commit Hook jetzt das Deployment anders triggern. Ich mag Trigger per HTTP-Request. In diesem Fall: ein Einzeiler-PHP in der Galactic Developments Website (Name lang und geheim, quasi das Passwort im Namen, Security by Obscurity), das ein lokales Shellscript startet, das wiederum "svn update" macht. Drei Einzeiler hintereinander. Man muss noch die Benutzer-Grenze überwinden vom wwwdata-User des Apache zum Eigentümer des Repositories. Deshalb wird das Shellscript mit sudo ausgeführt. Dafür eine Zeile in /etc/sudoers. Bei jedem svn commit ruft der post-commit Hook das update PHP-Script in der Zielwebsite per wget ("-O -" nicht vergessen) auf.
Dann noch DNS für www.galactic-developments.de umbiegen von rama.wolfspelz.de auf fred.wolfspelz.de und Galactic Developments ist umgezogen.
Das hört sich alles locker flockig an, hat mich aber mehrere Tage gekostet. Es gibt fast keine Anleitungen für libvirt/kvm OHNE lokales Display und ohne VNC. Auch virt-manager usw. alles nett gemeint, aber ich will kein Desktop auf meinem Server nur zum Installieren. (Wer bis hier gelesen bekommt von mir ein nagelneues Notebook). Genauso das Netzwerk: entweder es wird nicht erwähnt, was blöd ist, wenn man die VM vom Netzwerk installieren will oder es wird bridge-Networking vorgeschlagen, was bei mir einfach nicht wollte. Dabei geht das "default" Netzwerk super. Man muss es nur anschalten. Das könnte mal irgendwo stehen. Ein qemu-Hook statt bridge-Netz sehe ich nicht als Hack an, im Gegenteil.
PS: rama.wolfspelz.de war keine Frühstücksmargerine, sondern ein 50 km langes Alien-Raumschiff.
_happy_migrating()
Labels: devops, HTTP, Linux, SciFi, Web Server
21. September 2015
Feature Flags
![]() |
(Image: bytearrays.com) |
Feature flags (aka Feature Toggle, aka Feature Switch) let you enable program/web site features selectively. This is especially important in continuous delivery environments where code is always committed and deployed even if a feature is not ready for prime time. It can be useful if you have a large user base and want to introduce the feature incrementally by enabling the feature for sub-sets of users. Feature flags are useful in anything beyond toy apps.
Feature flags are not new. They are widely known since Martin Fowler blogged about the pattern. He did not invent them. Many good developers have been using feature flags or alike for a long time. But Martin Fowler recognized feature flags as a remarkable pattern. Writing about feature flags was a good idea, because other developers who are not aware of the pattern can learn from it. That was 2010.
Guess what, in 2006 a lonely Weblin programmer added feature flags to the Weblin portal. Weblin has been using feature flags from the start.
_happy_flagging()
Labels: Agile Development, Code, PHP
15. September 2015
ZEIT online Relaunch - Undo
Wie?
Mit Tampermonkey, eine Chrome Erweiterung. Tampermonkey führt auf jeder Webseite Javascript aus.
Bei ZEIT online muss man nur ein paar CSS Anweisungen verändern: den Hintergrund vom <body>-Tag wieder in weiß und der Rahmen vom Content-<div> weg:
body { background-color: #ffffff !important; }
.page__content { box-shadow: none; }
Man braucht noch etwas Javascript, um das CSS einzufügen. Hier das ganze Tampermonkey-Script für ZEIT online:
// ==UserScript==
// @name ZEIT
// @namespace http://wolfspelz.de/
// @version 0.1
// @description Restore white background
// @match http://www.zeit.de/*
// @copyright 2015+, wolfspelz
// ==/UserScript==
function addGlobalStyle(css) {
var head, style;
head = document.getElementsByTagName('head')[0];
if (!head) { return; }
style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
}
addGlobalStyle('body { background-color: #ffffff !important; } .page__content { box-shadow: none; }');
_happy_tampering()
Für Firefox: Greasemonkey
Labels: Chrome, Code, Firefox, Javascript
12. August 2015
Nie wieder Smooth Gestures für Chrome
Ich war immer sehr zufrieden mit der Chrome Extension "Gestures for Google Chrome". In letzter Zeit ist Gestures for Google Chrome anscheinend manchmal abgestürzt. Jedenfalls war sie immer wieder nicht aktiv, musste von Hand aktiviert werden.
Ich hatte noch von früher "Smooth Gestures" installiert, aber nicht aktiv. Probeweise mal wieder aktiviert. Macht in allen Tabs haufenweise Requests an yieldsquare.com (gefühlt 10 pro Sekunde).
Also: nie mehr aus Versehen zu Smooth Gestures greifen.
_happy_gesticulating()
6. August 2015
Minimalinvasiver Bootstrap Bestätigungsdialog (Confirm Modal Dialog)
Ab und zu braucht man bei Webanwendungen einen Bestätigungsdialog, bevor die Benutzerin eine Aktion auslöst, zum Beispiel "Do you really want to delete …"
Das geht mit Bootstrap sehr schlank und fast ohne Änderungen am Code. Kein Umstellen eines Links auf Button mit click-Aktion, kein Aufruf einer Javascript Dialog-Klasse, keine extra Funktionen als Callbacks, die auf Dialog-Button-OK oder –Abbrechen reagieren, sondern…
…etwas HTML (für den Dialog) und 2 Zeilen JavaScript zum Verdrahten.
Der Trick: Angenommen es gibt einen Link, dem der Confirm-Dialog vorgeschaltet werden soll. Das href-Attribut des Links wird zum "OK"-Button des Dialogs weitergereicht und der Link stattdessen zum Öffnen des Dialogs benutzt.
Ein Klick auf:
Delete
<a href="/Offer/Delete">Delete</a>
würde das Angebot (Offer) sofort löschen. Das soll durch einen Bestätigungsdialog abgesichert werden:
Dafür muss man 3 Dinge tun:
1. Dem Link sagen, dass er den Dialog aufrufen soll
<!—data-target und data-toggle aktivieren den Dialog beim Klick-->
<a href="/User/Delete" data-target="#ConfirmDialog" data-toggle="modal" id="DeleteButton">Delete</a>
2. Den Dialog definieren (irgendwo im Body)
<!-- Modal dialog -->
<div class="modal fade" id="DeleteDialog" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">Echt jetzt?</h4>
</div>
<div class="modal-body">Willst du das Angebot wirklich löschen?</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary btn-ok">OK</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Abbrechen</button>
</div>
</div>
</div>
</div>
3. Alles verdrahten:
// Beim ursprünglichen Link:
$('#DeleteButton').each(function () { $(this)
// Link als data-href sichern
.data('href', $(this).attr('href'))
// Link durch # entschärfen
.attr('href', '#');
});
// Beim Öffnen des Dialogs:
$('#DeleteDialog').on('show.bs.modal', function (e) { $(this).find('.btn-ok')
// …das gesicherte href-Attribut zum OK-Button weiterreichen
.attr('href', $(e.relatedTarget).data('href'))
// Beim OK-Klick zum href navigieren
.click(function () { location.href = $(this).attr('href'); });
});
Das sieht viel aus, aber in der Praxis schreibt sich das so:
$('#DeleteButton').each(function () { $(this) .data('href', $(this).attr('href')) .attr('href', '#'); });
$('#DeleteDialog').on('show.bs.modal', function (e) { $(this).find('.btn-ok') .attr('href', $(e.relatedTarget).data('href')) .click(function () { location.href = $(this).attr('href'); }); });
_happy_confirming()
PS: Nur eins der vielen kleinen Themen, die so ein Web-Projekt aufwirft: www.essenbeifreunden.com
Labels: Code, HTML/CSS, Javascript