Montag, 30. November 2020

WSL - ein paar Notizen zur Verwendung

Es gibt eine Menge im Netz zum WSL, aber vieles ist nicht klar mit Versionshinweisen beschrieben. Ich habe etwas mit WSL herum gespielt und hier meine Notizen dazu.

Versionen

Windows Server 2019: unterstützt nur V1, Tools: wsl.exe, wslconfig.exe, keine Store - nur manuelle Installation der (älteren) Distributionen.

Windows 10: unterstützt V1 und V2, Tools: wsl.exe mit erweitertem Umfang

Version 1: keine virtuelle Netzwerkkarte, verwendet direkt das Hostnetzwerk

Version 2: eine virtuelle Netzwerkkarte (bei jedem Neustart neue IP Adresse, Bereich 172.x.x.x) für alle Distributionen, besserer Kernel

Hier der offizielle Vergleich von MS.

Zugriff mit der virtuellen Maschine

wsl.exe öffnet quasi das "Terminal" ssh braucht man für die "Bedienung" nicht. 

Im Zusammenhang mit dem Thema "Kommandozeile" lohnt sich ein Blick auf Windows Terminal, dies ist seit kurzem über Windows Store installierbar.

Alle Datenträger vom Host sind direkt erreichbar (/mnt/c/...)

Die Ports aus der virtuellen Maschine werden an den Host durchgereicht, man kann über localhost:port oder 127.0.0.1:port zugreifen. Will man aus dem Netzwerk über den Host auf Ports in der virtuellen Maschine zugreifen, ist das Vorgehen bei V1 und V2 unterschiedlich. Die virtuelle IP ist aus dem Netzwerk nicht direkt erreichbar (NAT). 

Die Ports kann man mit ss -lntu innerhalb WSL V2 anzeigen, netstat und lsof sind nicht installiert (und funktionieren wohl nicht?). In WSL V1 habe ich keine Port Ausgabe hinbekommen, die Meldung klingt so, als ob im Kernel V1 etwas nicht implementiert ist.

Interessant: 

  • Aus dem ubuntu Subsystem heraus kann man direkt Windows Programme starten.
  • Mit einer kleinen Vorbereitung geht das auch umgekehrt, siehe diese Beschreibung.
  • In Windows kann man mit bash -c "Kommando" auch direkt Linux Befehle ausführen.

Die Distributionen (Ubuntu, debian) in WSL haben offenbar generell kein init System (wie systemd) aber eventuell kann man darauf auch verzichten. Mann kann den WSL und Prozesse darin direkt über die Windows Aufgabenplanung (Taskscheduler) starten.

Eine Kommando in Windows mit wsl.exe an WSL übergeben liefert die Ausgabe an Windows zurück. Die Ermittlung der IP Adresse gibt uns dafür ein paar Beispiele.  

Die einfachste Variante, funktioniert in CMD und Powershell - hat allerdings ein Leerzeichen am Ende. Dies kann man in PS einfach abschneiden (Befehl liefert String).trim()
wsl hostname -I

Ich habe die anderen Varianten mal zur Dokumentation und als Beispiel stehen lassen:

cmd Variante (fragt die wsl Umgebung ab, funktioniert aber nicht in powershell. Anmerkung: ^ ist ein Escape Zeichen der batch Umgebung)

WSL -d debian -- ip addr show eth0 ^| grep -oP '(?^<=inet\s)\d+(\.\d+){3}'

Powershell Variante Anmerkung: ` ist das Escape Zeichen in Powershell. Der Code braucht eine zweite Zeile!

(wsl -- ip addr show eth0 `| grep 'inet ') -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
$matches[0]


Installation und Konfiguration

Das Root Dateisystem jeder Linux Distribution wird in einer dynamischen 256GB VHDX Datei installiert. Den Speicherort kann man sich in Powershell so ausgeben lassen:

& cmd "/c dir %LOCALAPPDATA%\Packages\$((Get-AppxPackage -Name "*debian*").PackageFamilyName)\LocalState"

Statt über die interaktive Installation über den Store kann man die Pakete auch manuell herunterladen. Achtung: Das praktische Ergebnis (November 2020) ist anders, als die über den MS Store. Die Versionen sind viel älter!

Und offenbar teilweise sogar unvollständig:

  • In einer Variante fehlte wget und gnupg 
  • Die öffentlichen Zertifikaten waren alt oder nicht vorhanden! Ein apt install ca-certificates behebt das Problem.

Mit der kurzen url von dieser Seite geht das auch mit Powershell. 

Get-AppxPackage *Ubuntu*|Remove-AppxPackage
Get-AppxPackage *debian*|Remove-AppxPackage
Invoke-WebRequest -Uri https://aka.ms/wsl-debian-gnulinux -OutFile Debian.appx -UseBasicParsing
Add-AppxPackage .\Debian.appx

Man kann in WSL V2 auch komplette Distributionen exportieren (einpacken) und wieder importieren.

Der Windows Server hat keinen Store, die Installation funktioniert nur so wie hier beschrieben

Der Server 2019 Version kennt anstatt Enable-WindowsOptionalFeature.

Install-WindowsFeature -Name Microsoft-Windows-Subsystem-Linux

Die Hyper-V Umgebung

Ob Hyper-V schon aktiv ist kann man mit diesem Powershell Einzeiler testen:

(gcim Win32_ComputerSystem).HypervisorPresent

Ob die Hardware Hyper-V und damit auch WSL unterstützt kann man mit einem Powershell Einzeiler testen:

$list=@('Name', 'SecondLevelAddressTranslationExtensions', 'VirtualizationFirmwareEnabled', 'VMMonitorModeExtensions');Get-CimInstance -ClassName win32_processor -Property $list|Format-List $list

Ich habe diesen Test in einer virtuellen Maschine (Hyper-V) durchgeführt. Hier muss man auf dem Hyper-V Host die Virtualisierung an die Maschine "weiterreichen":

$vm=Get-Vm -Name <MaschineName>
Stop-Vm $vm
Set-VMProcessor $vm -ExposeVirtualizationExtensions $true
Start-Vm $vm


Die Ports

Achtung: Das Verhalten der Portweiterleitung ist unmittelbar nach der Einrichtung und nach einem Neustart unter Umständen komplett anders! 

Irgendwie gelingt es relativ leicht, dass man sich das Portmapping aus WSL heraus auf 127.0.0.1 zerschießt - ein netsh interface portproxy reset bewirkt dies zuverlässig. 

Hat man einmal einen Portproxy eingerichtet, funktioniert das Ganze nach einem Neustart nicht mehr. Man muss alles löschen und neu einrichten. Will man portproxy Einträge wieder löschen, kann man dies auch einzeln mit delete v4tov4 listenport=8083 tun! Dabei bleibt offenbar das (nicht sichtbare?) default Mapping erhalten. Löscht man den Eintrag für portproxy, stellt ein Neustart die ursprüngliche Funktion wieder her. 

Die Lösung für meine beobachteten Probleme liegt darin, den portproxy nicht auf localhost einzurichten (obwohl dies zunächst funktioniert) sondern auf die WSL eth0 Adresse. Hier ein Beispiele, die ich im Weiteren auch verwendet habe: 

  1. Artikel WSL Port forwarding 
  2. Artikel auf superuser

Mit tasklist | findstr wslhost kann man nachschauen auf welcher PID wsl arbeitet, mit netstat -aon | findstr <Suchstring> kann man den Prozess oder das Port darstellen. Die Prozesse innerhalb von wsl werden aber separat geführt. Mir ist es noch nicht die gesamte Prozesskette darzustellen.

Die wsl Kommanozeile

Es gibt einen Unterschied in der Verarbeitung zwischen dem Parameter -e und -- 

  • Bei -- kann man mehrere Befehle übergeben, getrennt mit Semikolon Befehl1;Befehl2,
  • das funktioniert offenbar bei -e nicht!
  • Gibt man den Linux Account mit:  -u username - funktioniert die Übergabe mehrere Befehle aber nicht mehr.

Empfehlung: Einfach eine Scriptdatei machen, das funktioniert viel einfacher als sich mit escapen und Variablenauflösung herumzuschlagen. Das Konstrukt wsl -e bash Script.sh funktioniert in gleicher Art in CMD, Powershell.


Sonntag, 22. November 2020

WSL - Windows Linux - wie macht man das?

Ich habe mich etwas mit Windows Subsystem Linux beschäftigt und versucht einen produktiven Ablauf für Setup und Verwendung zu finden. 

Als Ergebnis gibt es auf meiner GitHub Seite ein Powershell Script, welches den automatischen Start von WSL und einer Applikation darin bewerkstelligt. Ich werde dieses Script sicher aktualisieren und erweitern, eine kurze Anleitung zur Verwendung findet sich am Ende des Artikels.

Dieser Artikel ist die Mitschrift der Installation und Einrichtung von WSL und meiner ersten Versuche. Der Code ist eher prinzipiell und nicht unbedingt fehlertolerant.

Grundeinrichtung

Update 4.8.2021

Wenn man das Update KB5004296 installiert hat, kann man im aktuellen Windows 10 wohl einfach so in der Powershell Konsole installieren - dies war bisher nur mit der Insider Preview möglich:

wsl --install

Mit dem Befehl „--install“ werden die folgenden Aktionen ausgeführt (Quelle):

  • Die optionalen Komponenten von WSL und Plattform für virtuelle Computer werden aktiviert.
  • Der aktuelle Linux-Kernel wird heruntergeladen und installiert.
  • WSL 2 wird als Standard festgelegt.
  • Eine Linux-Verteilung wird heruntergeladen und installiert (möglicherweise ist ein Neustart erforderlich) .
  • Standardmäßig ist die installierte Linux-Verteilung Ubuntu. Dies kann mit wsl --install -d <Distribution Name> geändert werden.

Unter Windows 10 kann man das Feature WSL entweder per GUI oder per Powershell installieren. Zwei optionale Feature müssen aktiviert werden:

Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform,Microsoft-Windows-Subsystem-Linux

Danach ist ein Neustart fällig.

Das Admin-Tool für Windows Subsystem Linux ist wsl.exe. Damit kann man auch testen ob die Installation erfolgreiche war und aktive Distributionen und deren Status auflisten:

wsl -l -v

Es ist jetzt noch ein Kernelupdate fällig (auch bei 20H2)! 

Bevor man eine Distribution installiert sollte man die default WSL Version 2 setzen. 

wsl --set-default-version 2

Danach installiert man über den Windows Store eine Linux Distribution (debian). Die Installation ist immer zweistufig: download des appx Packetes und anschließend automatische Installation beim ersten Start. Beide Schritte entweder über suchen und zwei Klicks im Store direkt oder über zwei Powershell Befehle. Scheinbar sind die MS Store Versionen neuer als die auf der Download Seite!

Der Windows Store verhielt sich bei mir manchmal zickig: Es passiert beim Button drücken passiert nichts!? Es gibt zahlreiche Beiträge und einen extra Link in den Windows Einstellungen "Fehlerbehebung bei Microsoft Store Apps". Es gibt das cmd Programm wsreset.exe.

Die finale Installationroutine startet das Subsystem sofort und fragt Linux User und Passwort ab. 

Jeder weitere Aufruf von wsl.exe öffnet ein "Terminalfenster", der Erste startet das Subsystem.

wsl -d debian

Die Grundlage ist geschaffen und WSL wartet auf ein praktisches Beispiel: 

Anwendung (FHEM) in WSL installieren und starten

Für die FHEM Installation braucht man vorher noch (kann sich offenbar täglich ändern)

sudo apt install wget gnupg

danach funktioniert der debian easy way, allerdings wird FHEM am Ende nicht gestartet. 

Hinweis 2024: Die wsl ubuntu Distribution arbeitet mit systemd, fhem wird wie gewohnt gestartet wenn man wsl startet. Die folgende Fehlerbehebung ist in ubuntu nicht notwendig.

Es gibt eine Fehlermeldung am Ende, der Grund: Die debian Distribution enthält kein aktives init System (Systemd). Unschön ist, dass diese Fehlermeldung im dpkg status gespeichert bleibt und fortan jeder Befehl mit dpkg oder apt diesen Fehler anzeigen wird. 

Deswegen sollte man diesen Fehler unbedingt korrigieren:

sudo sed -i '/^Package: fhem/n;s/Status: install ok half-configured/Status: hold ok installed/' /var/lib/dpkg/status

Den Erfolg kann man leicht testen, der Fehler sollte verschwunden sein.

sudo apt install -f

Der sed Befehl 

  • patched die Datei direkt, 
  • er sucht die Zeile "Package: fhem" und 
  • ersetzt in der nächsten Zeile den Fehler. 

Der Start von FHEM benötigt zwei Befehlszeilen, mir ist das nur über einen Script Datei gelungen. Es ist wichtig diese Datei Linux konform zu erstellen. Die Windows Taste + cmd oder Powershell öffnet die Sitzung im Userpfad. Ein anschließendes wsl öffnet die Linux Sitzung im Userpfad. Jetzt einfach mit nano start.sh die Datei mit diesem Inhalt erstellen:

cd /opt/fhem
perl fhem.pl fhem.cfg

Das Script als Startbefehl übergeben und die Linux Distribution mit dem User fhem starten.

wsl -u fhem -d debian -e bash start.sh

Zugriff auf Ports innerhalb WSL

Um auf das Netzwerk in WSL zuzugreifen, kann man vom Host einfach auf localhost(127.0.0.1) zugreifen. Die Ports von WSL werden an diese Hostadresse geleitet (WSL 1 und 2).

http://localhost:8083

Will man aus dem restlichen Netzwerk auf FHEM (den WSL 2 Service) zugreifen, muss man einen PortProxy einrichten und die Ports in der Firewall freigeben. Dafür braucht man erhöhte Rechte, also Powershell im Administratormodus starten.

Anmerkung: Ich bin nicht sicher ob ich die Sache mit dem Portproxy und den Adressen richtig verstanden habe. Aber auf die Art wie ich es gelöst habe, funktioniert es zuverlässig. Im nächsten Beitrag habe ich noch meine Versuche und Erkenntnisse dokumentiert.

Da sich die IP Adresse bei jedem Neustart von WSL 2 ändert, muss man dieses Script bei jedem Start ausführen! Ich habe verschiedene Varianten zur Ermittlung der IP gefunden.

#$cAddr=(wsl -- ip addr show eth0 `| grep 'inet ') -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
#$cAddr=(bash.exe -c "ip addr show eth0 | grep 'inet '") -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
#$cAddr=$matches[0]
$cAddr=(wsl hostname -I).Trim()    # entferne Leerzeichen am Ende
$ports=8083,1883                   # Array mit allen Ports
if (netsh interface portproxy show all){netsh interface portproxy reset}
Foreach ($port in $ports){
   netsh interface portproxy add v4tov4 listenport=$port connectport=$port connectaddress=$cAddr
}

Die Firewall Rules braucht man nicht bei jedem Start neu machen

New-NetFireWallRule -DisplayName 'WSL Firewall Unlock' -Direction Outbound -LocalPort $ports -Action Allow -Protocol TCP
New-NetFireWallRule -DisplayName 'WSL Firewall Unlock' -Direction Inbound -LocalPort $ports -Action Allow -Protocol TCP

Sind die Regeln einmal vorhanden, kann man sie mit einem Befehl bez. der Ports modifizieren.

Set-NetFirewallRule -DisplayName 'WSL Firewall Unlock' -LocalPort $ports

Automatischer Start beim Windows Start

Ich habe ein Powershell Script erstellt, welches das komplette Setup erledigt. Nach dem Download in Zeile 3 kann man das Script natürlich noch anpassen.

Zur Vorbereitung braucht man vier Zeilen:

mkdir c:\scripts -force
cd c:\scripts
wget -O c:\scripts\SetupStartWsl.ps1 https://raw.githubusercontent.com/heinz-otto/Powershell/master/SetupStartWsl.ps1
Set-ExecutionPolicy RemoteSigned
.\SetupStartWsl.ps1

Das Setup Script erledigt 4 Schritte:

  1. Erzeugung des Shell Scripts für den Start innerhalb WSL. 
  2. Erzeugung des Powershell Scripts für den Taskscheduler, 
    • welches das Script aus 1. mit wsl startet, 
    • den Portproxy einrichtet und 
    • die FirewallRegeln anpasst.
  3. Firewall Regel als Grundlage erstellen.
  4. Registrierung der Aufgabe (Taskscheduler) beim Systemstart mit erhöhten Rechten das Script aus 2. auszuführen.

Man könnte noch folgendes einbauen:

  • die verwendeten Ports beim Start des wsl auslesen
  • eventuell eine Startverzögerung berücksichtigen 

Doku zu den Powershell cmdlets: Task mit Powershell


Mittwoch, 18. November 2020

Schreibe einen Patch

da ich jedes mal wieder überlegen und basteln muss - hier ein kurzes Howto - aufbauend auf das HowTo im Wiki.

Am einfachsten nimmt man sich vielleicht irgendeine virtuelle Maschine mit debian drauf. 

Man benötigt dafür keinen SVN Account!

Was man braucht ist nur ein Tool:

sudo apt update
sudo apt install subversion

Dann erstellt man eine Arbeitskopie im aktuellen User Home Directory.

svn checkout https://svn.fhem.de/fhem/trunk/fhem ~/fhem-code

Jetzt macht man seine gewünschte Änderung, am einfachsten mit nano (hier gibt es ein paar nützliche Tastenkürzel) Zum arbeiten macht es sich einfacher, wenn man im aktuellen "Working-Copy" Directory steht! Nach getaner Änderung lässt man sich den Patch anzeigen:

cd ~/fhem-code
svn diff

bzw. erstellt man gleich eine patch Datei in seinem Homeverzeichnis mit einem sprechenden Namen.

svn diff > ~/cref_motd.patch

Will man den Original Zustand der gesamten Arbeitskopie wiederherstellen:

svn revert --recursive .

Man kann die aktuellen Dateien aus dem SVN holen, treten Konflikte auf, kann man diese mit tf überschreiben.

svn update

Ein erneutes checkout holt zwar Änderungen vom Server, überschreibt aber lokale Änderungen nur wenn neue Versionen auf dem Server vorliegen!

Den eigene Patch wieder anwenden und testen:

svn patch ~/cref_motd.patch

Ist man fertig und kann von der Maschine nicht veröffentlichen, kopiert man sich das schnell auf den Arbeits PC:

scp ~/cref_motd.patch user@host:

Code Einchecken

Wie es geht steht hier im Wiki. Die Einrichtung der Umgebung steht auf der Webseite. Ich brauche nur trunk/fhem .
cd ~/fhem-ssh
svn update

Man kann den Code komfortabel mit notepad++ und dem NppFTP Plugin von Windows aus über ssh auf einer linux Umgebung editieren. 

Hat man die Änderungen fertig und getestet, erfolgt nochmal eine Überprüfung auf Konflikte mit eventuellen aktuellen Änderungen und dann commit. 

svn diff
svn commit -m "Dateiname:Beschreibung"

Da man dies selten tut, kann man die alten Befehle aus der Versenkung holen: 

history|grep 'svn'
grep "svn co " ~/.bash_history

Man kann sich vom aktuellen Pfad oder von einem anderem Pfad auch den Stand anzeigen lassen:

svn info
svn info ~/fhem-neu

...

Dienstag, 17. November 2020

Wake On Lan über "Dritte"

Zum Thema Wake On Lan habe ich ja schon ein paar Artikel geschrieben. Es gibt Situationen, da erreicht das Magic Paket nicht direkt sein Ziel. Falls also auch der "directed Broadcast" nicht funktioniert, ist vielleicht der "Agent" im Zielnetz eine Lösung!?

Auslöser für diese Notiz war dieser Beitrag im Forum.

Ein Magic Paket aus einer MAC Adresse zu bauen ist keine große Wissenschaft, dieses Paket muss man dann einfach per UDP und Port 9 ins Zielnetz schicken. Viel Code ist zur Lösung nicht nötig, das Meiste ist wie immer das User Interface und Fehlerbehandlung. 

Mir fallen drei Lösungsansätze ein, alle benötigen keine erhöhten Rechte!

Voraussetzung: ssh Verbindung mit public Key ist eingerichtet und funktioniert!

Linux Host

Auf der Suche nach einem simplen Script bin ich nur bei einer Perl Lösung fündig geworden, eine Lösung mit netcat werde ich noch bereitstellen. 

Das Setup auf dem "Remote Agenten" kann man dann auch gleich per ssh machen:

ssh user@host 'wget -qO wakeonlan https://raw.githubusercontent.com/jpoliv/wakeonlan/master/wakeonlan;chmod +x wakeonlan'

Das Script wird heruntergeladen und ausführbar gemacht. Dann ist die Verwendung simpel: 

  • mac Adresse übergeben
  • Parameter -q für quiet Modus
  • Parameter -i für eine directed Broadcast Adresse.
ssh user@host ./wakeonlan -q 12:34:56:AB:CD:EF

Windows Host

Ich hatte da mal ein PowerShellScript gemacht. Windows kann auch ssh, also kann man auch per ssh die Einrichtung und Steuerung vornehmen.

Fritzbox und TR064

Falls die Fritzbox als zentraler Router dient und die MAC Adressen dort registriert sind, kann man auch die Fritzbox benutzen um das Gerät per WOL zu starten. Per FHEM geht das simpel. Es gibt auch Powershellscripte dafür.

get <FritzBoxName> tr064Command Hosts:1 hosts X_AVM-DE_WakeOnLANByMACAddress NewMACAddress "12:34:56:78:9A:BC"

Definition in FHEM

Das WOL Modul in FHEM bietet mittlerweile den CMD Modus. Hier kann man separate Befehle zum aufwecken angeben, das Ganze auch über ssh (siehe den Link oben). 

In wolCmd steht ein FHEM Befehl. Der Platzhalter $MAC wird bei der Ausführung durch die mac Adresse in der Definition ersetzt.

Beispiel mit der Fritzbox:

Das Gerät muss in der Fritzbox registriert sein! Die Fritzbox kann Broadcast nur im eigenen Netzwerk! 

attr WolDevice wolCmd get Fritzbox tr064Command Hosts:1 hosts X_AVM-DE_WakeOnLANByMACAddress NewMACAddress $MAC

Beispiel mit Remote Host und ssh

Wir brauchen 3 Dinge - ausgeführt so als Block in der Raw Definition:

  1. Das Programm/Script auf dem Agenten,
  2. den Shell Befehl der auf dem Agenten ausgeführt werden soll,
  3. den sshHost in üblicher Form.

"ssh user@host 'wget -qO wakeonlan https://raw.githubusercontent.com/jpoliv/wakeonlan/master/wakeonlan;;chmod +x wakeonlan'"
attr WolDevice wolCmd "./wakeonlan -q $MAC"
attr WolDevice sshHost user@host


CodeSpace