[Patch] zuverlässigere Netzwerkinstallation

Antworten
Martin von Wittich
Beiträge: 16
Registriert: 11 Jun 2010, 15:45

[Patch] zuverlässigere Netzwerkinstallation

Beitrag von Martin von Wittich »

Hi,

wir haben bei Windows 7-Installationen früher häufiger die Erfahrung gemacht, dass Installationen mit aktiver Netzwerkinstallation (winpeNetworkMode=True) bei unseren Kunden trotz vorhandener Netzwerktreiber fehlschlagen. Die Ursache ist, dass die Netzwerkinstallation für alle Netzwerkkartentreiber, die von der ID her zur Netzwerkkarte passen, drvload-Anweisungen in die work.cmd einfügt:

Code: Alles auswählen

drvload <Treiber 1>
drvload <Treiber 2>
...
mount
setup
Es kann passieren, dass auf die Art und Weise zuerst ein funktionierender Treiber geladen wird, der anschließend direkt durch einen nicht funktionierenden Treiber ersetzt wird. Anschließend versucht das Script, die Freigabe zu mounten, was natürlich fehlschlägt; dann wiederholt es alle drvload-Anweisungen, was das Problem natürlich nicht löst. Infolgedessen haben wir die Netzwerkinstallation in unserem Windows 7-Paket dann einfach komplett entfernt, um diesem Fehler vorzubeugen.

Bei Windows 8 sind wir aber jetzt auf die Netzwerkinstallation angewiesen. Bei Windows 7 hatten wir nämlich die install.wim in mehrere *.swm-Images aufgeteilt, weil Debian nicht richtig mit deb-Paketen > 2 GB zurechtkommt; dieses Feature hat Microsoft bei Windows 8 aus unbekannten Gründen entfernt, sodass wir das Image für Windows 8 nicht mehr splitten können. Da unser Image mit integrierten Updates aber > 4 GB groß ist, ist es jetzt auch zu groß für die FAT32-Partition, die von opsi für die Installation verwendet wird.

Daher habe ich die Netzwerkinstallation in unserem Windows 8-Paket so umgeschrieben, dass er die verfügbaren Treiber in einer Schleife durchläuft, und sie einzeln ausprobiert:

Code: Alles auswählen

if mount then setup (erster Versuch mit integrierten Treibern)
drvload <Treiber 1>
if mount then setup
drvload <Treiber 2>
if mount then setup
...
error
Die entsprechenden Änderungen an der setup.py wollte ich eigentlich an dieses Posting anhängen, aber das Forum erlaubt es nicht :(
Das Kontingent für Dateianhänge ist bereits vollständig ausgenutzt.
Dann halt als Text:

Code: Alles auswählen

--- setup.py.orig2	2013-06-05 19:37:06.000000000 +0200
+++ setup.py	2013-06-05 19:16:00.000000000 +0200
@@ -426,12 +426,22 @@
 	logger.notice("Creating work.cmd")
 	f = open(target + '/opsi/work.cmd', 'w')
 	print >> f, "@echo off\r"
+	print >> f, "\r"
+	print >> f, "rem http://superuser.com/questions/80485/exit-batch-file-from-subroutine"
+	print >> f, "setlocal\r"
+	print >> f, "IF \"%selfWrapped%\"==\"\" (\r"
+	print >> f, "  REM this is necessary so that we can use \"exit\" to terminate the batch file,\r"
+	print >> f, "  REM and all subroutines, but not the original cmd.exe\r"
+	print >> f, "  SET selfWrapped=true\r"
+	print >> f, "  %ComSpec% /s /c \"\"%~0\" %*\"\r"
+	print >> f, "  GOTO :EOF\r"
+	print >> f, ")\r"
+	print >> f, "\r"
 	print >> f, "copy c:\\opsi\\unattend.xml x:\\unattend.xml >nul\r"
-	print >> f, ":init\r"
-	print >> f, "set mount_try_count=0\r"
 	print >> f, "c:\\opsi\\SetWallpaper.exe c:\\opsi\\opsibg.bmp >nul 2>nul\r"
 	print >> f, "echo Initializing ..... please wait ......\r"
 	print >> f, "wpeinit\r"
+	print >> f, "\r"
 	
 	if winpeNetworkMode and (depot._url.startswith('smb:') or depot._url.startswith('cifs:')):
 		match = re.search('^smb://([^/]+)/([^/]+)(.*)$', depot._url, re.IGNORECASE)
@@ -441,8 +451,7 @@
 		sn = match.group(2)
 		pn = match.group(3)
 		
-		print >> f, "goto mountshare\r"
-		print >> f, ":drvloadnetwork\r"
+		drivers = []
 		if os.path.exists(dstDriversDir):
 			storageControllerInfo = disk.getControllerInfo()
 			for filePath in findFiles(prefix = dstDriversDir, directory = dstDriversDir, includeFile = re.compile('\.inf$', re.IGNORECASE), returnDirs = False):
@@ -454,33 +463,54 @@
 						filePath = filePath[1:]
 					filePath = 'c:\\' + filePath.replace('/', '\\')
 					logger.notice("Adding to work.cmd: drvload %s\r" % filePath )
-					print >> f, "drvload %s\r" % filePath
+					drivers.append(filePath)
 				if storageControllerInfo and infFile.isDeviceKnown(storageControllerInfo['vendorId'], storageControllerInfo['deviceId']):
 					logger.info(u"Integrating winpe driver for storage controller: %s" % storageControllerInfo)
 					copy(os.path.dirname(filePath), dstPeDriversDir)
+		driversstr = ",".join(drivers)
 		
 		encodedPcpatchPassword = backend.getPcpatchPassword(hostId = clientId)
 		
-		print >> f, "goto mountshare\r"
-		print >> f, ":waitnet\r"
-		print >> f, "echo Waiting for the network ......\r"
-		print >> f, "ping -n 5 127.0.0.1 >nul\r"
-		print >> f, ":mountshare\r"
-		print >> f, "set /a mount_try_count=%mount_try_count%+1\r"
-		print >> f, "net use /y /delete * >nul\r"
-		print >> f, "ping -n 5 127.0.0.1 >nul\r"
-		print >> f, "c:\\opsi\\opsinetmount.exe --keyfile=c:\\opsi\\opsi-client-agent\\files\\opsi\\cfg\\config.ini --user=%s\\pcpatch --drive=o --share=\\\\%s\\%s --encrypted-pass=%s \r" % (hn, hn, sn, encodedPcpatchPassword)
-		print >> f, "if not %ERRORLEVEL%==0 (\r"
-		print >> f, "   if %mount_try_count%==5 goto drvloadnetwork\r"
-		print >> f, "   if %mount_try_count%==15 goto init\r"
-		print >> f, "   goto waitnet\r"
-		print >> f, ")\r"
-		print >> f, ":install\r"
-		print >> f, "o:%s\\%s\\installfiles\\setup.exe %s" % (pn.replace('/', '\\'), productId, "/unattend:x:\\unattend.xml\r")
-	else:
-		print >> f, ":install\r"
-		print >> f, "c:\\installfiles\\setup.exe /unattend:x:\\unattend.xml\r"
-	print >> f, "if not %ERRORLEVEL%==0 goto init\r"
+		print >> f, "set attempts=1\r"
+		print >> f, "call :iter\r"
+		print >> f, "call :list_iter :iter \"%s\"\r" % driversstr
+		print >> f, "set attempts=5\r"
+		print >> f, "call :iter\r"
+		print >> f, "call :list_iter :iter \"%s\"\r" % driversstr
+		print >> f, "echo.\r"
+		print >> f, "echo Kein passender Netzwerktreiber gefunden!\r"
+		print >> f, "echo Bitte kopieren Sie den richtigen Netzwerktreiber nach \\\\iserv\\driver\r"
+		print >> f, "echo und starten Sie die Installation neu.\r"
+		print >> f, "echo.\r"
+		print >> f, "pause\r"
+		print >> f, "exit /b\r"
+		print >> f, "\r"
+		print >> f, ":iter\r"
+		print >> f, "  if not \"%*\"==\"\" drvload %*\r"
+		print >> f, "  call :mount || exit /b 1\r"
+		print >> f, "  o:%s\\%s\\installfiles\\setup.exe %s" % (pn.replace('/', '\\'), productId, "/unattend:x:\\unattend.xml\r")
+		print >> f, "  exit\r"
+		print >> f, "\r"
+		print >> f, ":mount\r"
+		print >> f, "  for /l %%a in (1,1,%attempts%) do (\r"
+		print >> f, "    if not %attempts%==1 echo Mountversuch %%a von %attempts%\r"
+		print >> f, "    net use /y /delete * >nul\r"
+		print >> f, "    ping -n 5 127.0.0.1 >nul\r"
+		print >> f, "    c:\\opsi\\opsinetmount.exe --keyfile=c:\\opsi\\opsi-client-agent\\files\\opsi\\cfg\\config.ini --user=%s\\pcpatch --drive=o --share=\\\\%s\\%s --encrypted-pass=%s && exit /b\r" % (hn, hn, sn, encodedPcpatchPassword)
+		print >> f, "    ping -n 5 127.0.0.1 >nul\r"
+		print >> f, "  )\r"
+		print >> f, "  exit /b 1\r"
+		print >> f, "\r"
+		print >> f, "rem http://stackoverflow.com/questions/2524928/dos-batch-iterate-through-a-delimited-string\r"
+		print >> f, ":list_iter\r"
+		print >> f, "  rem Usage: call :list_iter :do_sub_for_each_item \"CSV of items\"\r"
+		print >> f, "  set foo=%1\r"
+		print >> f, "  set list=%~2\r"
+		print >> f, "  for /f \"tokens=1* delims=,\" %%i in (\"%list%\") do (\r"
+		print >> f, "    call %foo% %%i\r"
+		print >> f, "    if not \"%%j\" == \"\" ( call :list_iter %foo% \"%%j\" )\r"
+		print >> f, "  )\r"
+		print >> f, "  exit /b\r"
 	f.close()
 	
 	# Create startnet.cmd
Eine von diesem Code erzeugte work.cmd sieht z. B. so aus:

Code: Alles auswählen

@echo off

rem http://superuser.com/questions/80485/exit-batch-file-from-subroutine
setlocal
IF "%selfWrapped%"=="" (
  REM this is necessary so that we can use "exit" to terminate the batch file,
  REM and all subroutines, but not the original cmd.exe
  SET selfWrapped=true
  %ComSpec% /s /c ""%~0" %*"
  GOTO :EOF
)

copy c:\opsi\unattend.xml x:\unattend.xml >nul
c:\opsi\SetWallpaper.exe c:\opsi\opsibg.bmp >nul 2>nul
echo Initializing ..... please wait ......
wpeinit

set attempts=1
call :iter
call :list_iter :iter "c:\drv\7\e1c62x64.inf,c:\drv\8\e1c60x64.inf,c:\drv\9\e1c62x64.inf,c:\drv\10\e1c63x64.inf,c:\drv\11\e1c60x64.inf,c:\drv\12\e1c63x64.inf"
set attempts=5
call :iter
call :list_iter :iter "c:\drv\7\e1c62x64.inf,c:\drv\8\e1c60x64.inf,c:\drv\9\e1c62x64.inf,c:\drv\10\e1c63x64.inf,c:\drv\11\e1c60x64.inf,c:\drv\12\e1c63x64.inf"
echo.
echo Kein passender Netzwerktreiber gefunden!
echo Bitte kopieren Sie den richtigen Netzwerktreiber nach \\iserv\driver
echo und starten Sie die Installation neu.
echo.
pause
exit /b

:iter
  if not "%*"=="" drvload %*
  call :mount || exit /b 1
  o:\install\microsoft-windows-8-64\installfiles\setup.exe /unattend:x:\unattend.xml
  exit

:mount
  for /l %%a in (1,1,%attempts%) do (
    if not %attempts%==1 echo Mountversuch %%a von %attempts%
    net use /y /delete * >nul
    ping -n 5 127.0.0.1 >nul
    c:\opsi\opsinetmount.exe --keyfile=c:\opsi\opsi-client-agent\files\opsi\cfg\config.ini --user=iserv\pcpatch --drive=o --share=\\iserv\deploy --encrypted-pass=entfernt && exit /b
    ping -n 5 127.0.0.1 >nul
  )
  exit /b 1

rem http://stackoverflow.com/questions/2524928/dos-batch-iterate-through-a-delimited-string
:list_iter
  rem Usage: call :list_iter :do_sub_for_each_item "CSV of items"
  set foo=%1
  set list=%~2
  for /f "tokens=1* delims=," %%i in ("%list%") do (
    call %foo% %%i
    if not "%%j" == "" ( call :list_iter %foo% "%%j" )
  )
  exit /b

Produktiv im Einsatz war das Ganze noch nicht, aber bei mir im Test scheint es gut zu funktionieren.
Mit freundlichen Grüßen,
Martin v. Wittich

IServ GmbH
Bültenweg 73
38106 Braunschweig

Telefon: 0531-2243666-0
Fax: 0531-2243666-9
E-Mail: info@iserv.eu
Internet: iserv.eu
Benutzeravatar
d.oertel
uib-Team
Beiträge: 3327
Registriert: 04 Jun 2008, 14:27

Re: [Patch] zuverlässigere Netzwerkinstallation

Beitrag von d.oertel »

Hi,

gegen welche netboot produkt version ist der Patch erstellt ?

gruß
d.oertel


Vielen Dank für die Nutzung von opsi. Im Forum ist unser Support begrenzt.

Für den professionellen Einsatz und individuelle Beratung empfehlen wir einen Support-Vertrag und eine Schulung.
Gerne informieren wir Sie zu unserem Angebot.

uib GmbH
Telefon: +49 6131 27561 0
E-Mail: sales@uib.de


Martin von Wittich
Beiträge: 16
Registriert: 11 Jun 2010, 15:45

Re: [Patch] zuverlässigere Netzwerkinstallation

Beitrag von Martin von Wittich »

d.oertel hat geschrieben: gegen welche netboot produkt version ist der Patch erstellt ?
Eigentlich gegen win8-x64_4.0.3-2.opsi, aber ich merke gerade, dass er sich nicht anwenden lässt, wenn man ihn aus meinem Beitrag copy-pasted :/
Das Forum hat anscheinend die Tabs zerstört, das ist die Ursache. Versuch's mal mit dieser Version:

http://martin.von.wittich.support.iserv ... .patch.txt

Damit klappt das Patchen bei mir:

Code: Alles auswählen

iserv ~/martintest # patch setup.py < netzwerkinstallation.patch.txt 
patching file setup.py
Hunk #1 succeeded at 420 (offset -6 lines).
Hunk #2 succeeded at 445 (offset -6 lines).
Hunk #3 succeeded at 457 (offset -6 lines).
Ach ja, was mir gerade noch auffällt: mein Patch entfernt den else-Block, der greift, wenn die Netzwerkinstallation abgeschaltet ist. Für uns ist das egal, weil wir bei Win8 keine Installationen ohne Netzwerkinstallation unterstützen werden, aber grundsätzlich sollte der wohl eher drinbleiben.
Mit freundlichen Grüßen,
Martin v. Wittich

IServ GmbH
Bültenweg 73
38106 Braunschweig

Telefon: 0531-2243666-0
Fax: 0531-2243666-9
E-Mail: info@iserv.eu
Internet: iserv.eu
Benutzeravatar
d.oertel
uib-Team
Beiträge: 3327
Registriert: 04 Jun 2008, 14:27

Re: [Patch] zuverlässigere Netzwerkinstallation

Beitrag von d.oertel »

Hi,

ich habe da noch ein Verständnis Problem.
In der aktuellen Version von opsi ist es so, das für ein Gerät (PCI Kennung) nur ein Treiber integriert wird.
D.h. der von Dir beschriebene Fall, das zwei verschiedene Treiber im PE für das selbe Gerät geladen werden taucht nicht mehr auf.
Was passieren kann ist, daß das PE einen anderen Treiber braucht als das fertig installierte Win7. In diesem Fall muss der PE Treiber per dism in das PE integriert werden (siehe Getting Started Handbuch).

Mich würde also der Kontext interessieren in dem Ihr das Problem produziert.

gruß
d.oertel


Vielen Dank für die Nutzung von opsi. Im Forum ist unser Support begrenzt.

Für den professionellen Einsatz und individuelle Beratung empfehlen wir einen Support-Vertrag und eine Schulung.
Gerne informieren wir Sie zu unserem Angebot.

uib GmbH
Telefon: +49 6131 27561 0
E-Mail: sales@uib.de


Martin von Wittich
Beiträge: 16
Registriert: 11 Jun 2010, 15:45

Re: [Patch] zuverlässigere Netzwerkinstallation

Beitrag von Martin von Wittich »

d.oertel hat geschrieben: ich habe da noch ein Verständnis Problem.
In der aktuellen Version von opsi ist es so, das für ein Gerät (PCI Kennung) nur ein Treiber integriert wird.
Argh, stimmt, das hatte ich gar nicht bedacht. Wir haben in unserem System create_driver_links.py durch eine eigene Lösung ersetzt, die beliebig viele Treiber pro PCI-Kennung erlaubt. Damit haben wir das Problem gelöst, dass sich manche Treiber nur durch ihre Subsystem-IDs unterscheiden - bei create_driver_links hatten wir öfter das Problem, dass ein Treiber aus dem Driverpack von der Vendor- und Device-ID her passte, aber nicht die korrekten Subsystem-IDs hatte. Da create_driver_links bedingt durch die Symlinks nur einen Treiber pro PCI-Kennung erlaubt hat, konnte man keine zusätzlichen Treiber einbinden, die die nötigen Subsystem-IDs hätten.

Das Ganze funktioniert bei uns jetzt wie folgt:

1) Die Driverpacks-Treiber (Ordner driverpacks.net) und unsere eigenen (Ordner iserv) sind mit unserem System vorinstalliert; der Admin kann seine eigenen Treiber in dem Ordner custom hinterlegen:

iserv ~ # ll /srv/deploy/driver/*
/srv/deploy/driver/custom:
insgesamt 12K
drwxrwsr-x 2 root admins 4,0K 18. Feb 18:01 wnt5_x86-32/
drwxrwsr-x 2 root admins 4,0K 16. Jan 19:43 wnt6-x64/
drwxrwsr-x 2 root admins 4,0K 17. Jan 15:15 wnt6-x86/

/srv/deploy/driver/iserv:
insgesamt 12K
drwxr-xr-x 64 root root 4,0K 19. Feb 02:38 wnt5_x86-32/
drwxr-xr-x 12 root root 4,0K 18. Jan 02:38 wnt6-x64/
drwxr-xr-x 8 root root 4,0K 18. Jan 02:38 wnt6-x86/

/srv/deploy/driver/driverpacks.net:
insgesamt 12K
drwxr-xr-x 3 root root 4,0K 4. Jul 2012 wnt5_x86-32/
drwxr-xr-x 5 root root 4,0K 30. Aug 2012 wnt6-x64/
drwxr-xr-x 3 root root 4,0K 29. Aug 2012 wnt6-x86/

Wenn neue Treiber hinterlegt werden, braucht kein Script mehr per Hand aufgerufen zu werden.

2) Wenn opsi Windows installiert, sucht es seine Treiber nicht mehr in einem bestimmten Pfad (also sowas wie \\server\treiber\<vendorid>\<deviceid>), sondern übermittelt alle Geräte-IDs per RPC-Call an das Backend. Der Request sieht in unserem RPC-Debug-Log so aus:

2013-06-20 14:41:59.387 10.0.56.52 opsi linux bootimage 20120119 meth: iserv_getdrivers
2013-06-20 14:41:59.397 10.0.56.52 opsi linux bootimage 20120119 auth: host martin-w7-64
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 params=arr {
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 0 = "wnt6-x64"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 1 = arr {
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 0 = "pci/80EE:BEEF"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 1 = "pci/8086:100E:8086:001E"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 2 = "pci/80EE:CAFE"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 3 = "pci/8086:2668:8384:7680"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 4 = "pci/8086:7113"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 5 = "pci/8086:2448"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 6 = "pci/8086:2448"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 7 = "pci/8086:27B9:8086:7270"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 8 = "pci/8086:2829"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 9 = "pci/106B:003F"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 10 = "pci/8086:265C"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 11 = "hdaudio/8384:7680:8384:7680"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 12 = "usb/80EE:0021"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 13 = "usb/1D6B:0001"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 14 = "usb/1D6B:0002"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 15 = "custom"
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 }
2013-06-20 14:41:59.401 10.0.56.52 opsi linux bootimage 20120119 }

3) Das Backend übergibt die IDs an ein Perl-Script. Dieses Script durchläuft bei jedem Aufruf alle INF-Dateien, die es im Treiber-Ordner findet. Wenn es dabei auf eine neue INF-Datei stößt, die es noch nicht in einem früheren Durchlauf geparst hat, parst das Script diese Datei jetzt, und speichert die Hardware-IDs der INF-Datei in seinem Cache. Der Cache enthält für alle bekannten INF-Dateien im Treiberordner folgende Infos:
- vollständiger Pfad zur INF-Datei
- Dateigröße in Bytes
- mtime der Datei als UNIX-Timestamp
- Ein Array der Hardware-IDs

Anschließend durchsucht es den gerade aktualisierten Cache nach den IDs, die das Script per Parameter bekommen hat, und gibt die relativen Pfade auf stdout aus; das Backend gibt das als Array an den Client zurück:

2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 arr {
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 0 = "iserv/wnt6-x64/Virtualbox_Guest_Additions/VBoxVideo"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 1 = "iserv/wnt6-x64/Virtualbox_Guest_Additions/VBoxVideoWddm"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 2 = "driverpacks.net/wnt6-x64/x64/Server/L/Intel/2/Winx64/NDIS61"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 3 = "driverpacks.net/wnt6-x64/x64/Server/L/Intel/2/Win64/NDIS61"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 4 = "driverpacks.net/wnt6-x64/x64/Vista/L/Intel/2/NDIS61"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 5 = "iserv/wnt6-x64/Virtualbox_Guest_Additions/VBoxGuest"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 6 = "driverpacks.net/wnt6-x64/x64/All/C/Intel/1"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 7 = "driverpacks.net/wnt6-x64/x64/Win7/C/Intel/1"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 8 = "driverpacks.net/wnt6-x64/x64/All/M/Intel/1"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 9 = "iserv/wnt6-x64/Dell_Latitude_E5530_Free_Fall_Sensor/.deploy"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 10 = "iserv/wnt6-x64/Acer_TravelMate_P653MG_Free_Fall_Sensor/.deploy"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 11 = "iserv/wnt6-x64/Lenovo_ACPI/.deploy"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 12 = "driverpacks.net/wnt6-x64/x64/All/G_B/Intel/4/.deploy"
2013-06-20 14:41:59.879 10.0.56.52 opsi linux bootimage 20120119 }

Die Vorteile von der Lösung:
- Der Admin braucht kein Script aufrufen, nachdem er den Treiberordner verändert hat
- Beliebig viele Treiber pro Hardware-Kennung
- Das Script läuft dank der eigenen Cachedatei (und auch dem Linux-Cache) nach mehreren Aufrufen sehr schnell, sodass wir es uns leisten können, das bei jeder Installation aufrufen.

Mit Cache-Datei und Linux-Cache:
iserv ~ # time /usr/lib/iserv/deploy_indexdrv wnt5_x86-32 pci/8086:1e02
driverpacks.net/wnt5_x86-32/D/M/I7
driverpacks.net/wnt5_x86-32/D/M/I5
iserv/wnt5_x86-32/Textmode_Intel_7_AHCI
iserv/wnt5_x86-32/Textmode_Intel_7_1_AHCI
/usr/lib/iserv/deploy_indexdrv wnt5_x86-32 pci/8086:1e02 0,98s user 0,18s system 99% cpu 1,165 total

Mit Cache-Datei, aber ohne Linux-Cache:
iserv ~ # echo 3 > /proc/sys/vm/drop_caches
iserv ~ # time /usr/lib/iserv/deploy_indexdrv wnt5_x86-32 pci/8086:1e02
driverpacks.net/wnt5_x86-32/D/M/I7
driverpacks.net/wnt5_x86-32/D/M/I5
iserv/wnt5_x86-32/Textmode_Intel_7_AHCI
iserv/wnt5_x86-32/Textmode_Intel_7_1_AHCI
/usr/lib/iserv/deploy_indexdrv wnt5_x86-32 pci/8086:1e02 1,94s user 0,72s system 60% cpu 4,421 total

Ohne Cache-Datei und ohne Linux-Cache, d.h. alle INF-Dateien werden neu geparst (das passiert nur beim ersten Aufruf des Scripts):

iserv ~ # time /usr/lib/iserv/deploy_indexdrv wnt5_x86-32 pci/8086:1e02
driverpacks.net/wnt5_x86-32/D/M/I7
driverpacks.net/wnt5_x86-32/D/M/I5
iserv/wnt5_x86-32/Textmode_Intel_7_AHCI
iserv/wnt5_x86-32/Textmode_Intel_7_1_AHCI
/usr/lib/iserv/deploy_indexdrv wnt5_x86-32 pci/8086:1e02 31,69s user 1,04s system 86% cpu 37,861 total

Größe der Treiber:

iserv ~ # du -shc /srv/deploy/driver/*/wnt5_x86-32
4,0K /srv/deploy/driver/custom/wnt5_x86-32
5,9G /srv/deploy/driver/driverpacks.net/wnt5_x86-32
526M /srv/deploy/driver/iserv/wnt5_x86-32
6,4G insgesamt


Bei der Gelegenheit haben wir noch einen "custom"-Mechanismus eingebaut, bei dem ein Shellscript in jedem Treiberordner darüber entscheiden darf, ob der Treiber eingebunden wird oder nicht. Das nutzen wir bei WinXP-Textmode-Treibern, um die nur für genau die Rechnermodelle freizugeben, bei denen wir sie getestet haben (Textmode-Treiber verursachen auf den falschen Rechnern gerne Bluescreens), und um ACPI-Treiber einzubinden (create_driver_links konnte das damals nicht, und ich war zu faul, das bei uns sauber über das Parsing der INF-Dateien zu machen).

Ich sehe mal zu, dass ich den Code dafür demnächst hier poste. Ihr werdet da aber vermutlich einiges anpassen müssen, wenn ihr das übernehmen wollt (andere Pfade für die Cachedatei/Treiber), den Code in den Produkten werdet ihr wahrscheinlich in das Bootimage einbauen wollen (habe ich drauf verzichtet, ich wollte es nicht unnötig verändern) und den Support im Backend müsst ihr selber schreiben, weil das bei uns in PHP ist... das sollte aber sehr simpel sein, das ist nur einmal kurz den Request validieren, und der Rest macht das Perl-Script:

Code: Alles auswählen

  function iserv_getdrivers($drivertype, $devices)
  {
    auth_host();

    # check parameters
    $m_hex = "(?:(?i)[0-9a-f]{4})";
    $m_dev = "^(custom|(usb|pci|hdaudio)\/$m_hex:$m_hex((:$m_hex){2})?)$";
    if (!preg_match("/^([\w\d-]+)$/", $drivertype))
      throw new Exception("invalid driver type $drivertype");
    foreach ($devices as $d)
      if (!preg_match("/$m_dev/", $d))
        throw new Exception("invalid device string $d");

    # run deploy_indexdrv
    exec("/usr/lib/iserv/deploy_indexdrv $drivertype ".join(" ", $devices),
        $output, $ret);
    if ($ret != 0)
      throw new Exception("deploy_indexdrv failed");

    # return paths
    return $output;
  }
Mit freundlichen Grüßen,
Martin v. Wittich

IServ GmbH
Bültenweg 73
38106 Braunschweig

Telefon: 0531-2243666-0
Fax: 0531-2243666-9
E-Mail: info@iserv.eu
Internet: iserv.eu
Antworten