Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Einführung in den HPC Pack-Ausführungsfilter auf Linux-Computeknoten
Der Ausführungsfilter für Linux-Computeknoten wird in der Juni QFE-Version von HPCeingeführt. Sie ermöglicht es clusteradministratoren, angepasste Skripts (unter stamm) auf Linux-Computeknoten während einer anderen Phase der Auftrags-/Aufgabenausführung auszuführen.
Zwei typische Szenarien mit Ausführungsfiltern:
Auf Linux-Knoten mit integriertem Active Directory ist das Benutzername-Format in unterschiedlichen Formaten vorhanden. Mit dem Ausführungsfilter kann der Administrator das Benutzernamenformat anpassen, bevor der Auftrag/die Aufgabe ausgeführt wird. Übersetzen Sie beispielsweise den Benutzernamen aus dem Format "Domäne\Benutzer" in das Format "domain.user"
In der Regel verfügt jeder Benutzer über einen eigenen Privaten Ordner auf einer SMB-Freigabe. Mit dem Ausführungsfilter kann der Administrator ein Skript bereitstellen, um die SMB-Freigabe mit dem Domänenkonto des Benutzers bereitzustellen, sodass der Auftrag/die Aufgabe auf seine eigenen Daten in der Freigabe zugreifen kann und bevor der Auftrag beendet wird.
Aktivieren von Ausführungsfiltern
Der Ausführungsfilter auf Linux-Knoten kann durch Hinzufügen von Skriptdateien unter /opt/hpcnodemanager/filtersaktiviert werden. Derzeit unterstützt HPC Pack:
OnJobTaskStart.sh: Dieses Skript wird sofort ausgeführt, wenn die erste Aufgabe an den Linux-Knoten verteilt wird. Ab der momentanen Implementierung kann dieses Skript mehrmals ausgeführt werden, falls die Aufgabe parametrisch aufräumen ist. Möglicherweise müssen Sie diese Situation behandeln. Der Administrator kann dieses Skript nutzen, um die Knotenvorbereitung durchzuführen, z. B. das Bereitstellen einer Freigabe für den Benutzer.OnTaskStart.sh: Dieses Skript wird ausgeführt, wenn die Nachverfolgungsaufgabe an den Linux-Knoten verteilt wird. Der Administrator kann dieses Skript nutzen, um die Aufgabenausführungsumgebung wie einen WorkDir anzupassen.OnJobEnd.sh: Dieses Skript wird ausgeführt, wenn der Auftrag auf dem Linux-Knoten beendet wird. Der Administrator kann dieses Skript nutzen, um einige Bereinigungen zu erledigen.
Beachten Sie, dass die Filter aufgrund von Planungsrichtlinien/Netzwerkproblemen/Wiederholungen mehrmals für denselben Auftrag oder dieselbe Aufgabe ausgelöst werden können.
Anpassen von Ausführungsfiltern
Eingabe für die Ausführungsfilter
Die Eingabe für alle Ausführungsfilter erfolgt über standardeingabe im JSON-Datenformat. Die folgenden Beispiele sind:
Beispieleingabe für
OnJobTaskStart.sh:{ "m_Item1": { "JobId": 9299, "ResIds": [ 141 ], "TaskId": 170355 }, "m_Item2": { "affinity": [ 1 ], "commandLine": "echo specialword1", "environmentVariables": { "CCP_CLUSTER_NAME": "LN11-RH71-HN1", "CCP_COREIDS": "0", "CCP_EXCLUSIVE": "False", "CCP_ISADMIN": "1", "CCP_JOBID": "9299", "CCP_JOBNAME": "Test Basic OnJobTaskStart", "CCP_JOBTYPE": "Batch", "CCP_MPI_NETMASK": "10.156.60.0/255.255.252.0", "CCP_NODES": "1 LN11-RH71-LN2 1", "CCP_NODES_CORES": "1 LN11-RH71-LN2 1", "CCP_NUMCPUS": "1", "CCP_OWNER_SID": "S-1-5-21-1645912939-3214980066-801894016-500", "CCP_REQUIREDNODES": "", "CCP_RERUNNABLE": "False", "CCP_RETRY_COUNT": "0", "CCP_RUNTIME": "2147483647", "CCP_SERVICEREGISTRATION_PATH": "\\\\LN11-RH71-HN1\\HpcServiceRegistration", "CCP_TASKID": "1", "CCP_TASKINSTANCEID": "0", "CCP_TASKSYSTEMID": "170355", "HPC_RUNTIMESHARE": "\\\\LN11-RH71-HN1\\Runtime$" }, "stderr": null, "stdin": null, "stdout": null, "taskRequeueCount": 0, "workingDirectory": null }, "m_Item3": "hpclnpr11\\Administrator", "m_Item4": "Password", "m_Item5": null, "m_Item6": null }Der Inhalt für
m_Item1enthält grundlegende Auftrags- und Aufgaben-ID-Informationen.Der Inhalt für
m_item2enthält detailliertere Auftragsinformationen, die beschreiben, wie der Auftrag ausgeführt wird und mit welchen Parametern. DerenvironmentVariables-Block enthält auch den benutzerdefiniertenEnvironment Variables, der im Auftrag/der Aufgabe definiert wurde:
- Die Inhalte für
m_Item3undm_Item4sind der Benutzer und das Kennwort desRunasBenutzers des Auftrags. Bitte achten Sie darauf, wenn Ihr Ausführungsfilter diese Informationen verwendet (insbesondere das Kennwort).
Beispieleingabe für
OnTaskStart.sh:{ "m_Item1": { "JobId": 11274, "ResIds": [ 205 ], "TaskId": 206059 }, "m_Item2": { "affinity": [ 1 ], "commandLine": "echo specialword1", "environmentVariables": { "CCP_CLUSTER_NAME": "LN11-RH71-HN1", "CCP_COREIDS": "0", "CCP_EXCLUSIVE": "False", "CCP_JOBID": "11274", "CCP_JOBNAME": "", "CCP_JOBTYPE": "Batch", "CCP_MPI_NETMASK": "10.156.60.0/255.255.252.0", "CCP_NODES": "1 LN11-RH71-LN1 1", "CCP_NODES_CORES": "1 LN11-RH71-LN1 1", "CCP_NUMCPUS": "1", "CCP_OWNER_SID": "S-1-5-21-1645912939-3214980066-801894016-500", "CCP_REQUIREDNODES": "", "CCP_RERUNNABLE": "False", "CCP_RETRY_COUNT": "0", "CCP_RUNTIME": "2147483647", "CCP_SERVICEREGISTRATION_PATH": "\\\\LN11-RH71-HN1\\HpcServiceRegistration", "CCP_TASKID": "2", "CCP_TASKINSTANCEID": "0", "CCP_TASKSYSTEMID": "206059", "HPC_RUNTIMESHARE": "\\\\LN11-RH71-HN1\\Runtime$" }, "stderr": null, "stdin": null, "stdout": null, "taskRequeueCount": 0, "workingDirectory": null } }Beispieleingabe für
OnJobEnd.sh:{ "JobId": 9299, "JobInfo": null, "ResIds": [ 141 ] }
Ausgabe des Ausführungsfilters
Bei OnJobTaskStart.sh- und OnTaskStart.sh Filtern sollte die Ausgabe über die Standardausgabe zurück an den Nodemanager im formalen JSON-Format übergeben werden. Die Ausgabe mit neuen Auftragsinformationen beeinflusst das Auftragsverhalten. Und OnJobEnd.shStandardausgabe wirkt sich nicht auf das Auftragsverhalten aus. Neben der Standardausgabe sollten OnJobTaskStart.sh- und OnTaskStart.sh Filter mit Exitcode beenden 0, um eine erfolgreiche Ausführung anzugeben, andernfalls überspringt der Nodemanager den Start des Auftrags/der Aufgabe und gibt einen Fehler an den Planer zurück. Der Fehlercode kann in der Protokolldatei nodemanager.txtangezeigt werden. Weitere Informationen finden Sie im Abschnitt Problembehandlung bei Ausführungsfiltern Abschnitt.
Anpassen des Ausführungsfilters
Um die Ausführungsfilter anzupassen, rufen Sie die JSON-Daten ab, die aus der Standardeingabe in den Skripts übertragen werden, verwenden Sie die Daten, um einige Funktionen zu erfüllen, und verfassen Sie dann die Ausgabe-JSON über die Standardausgabe für OnJobTaskStart.sh und OnTaskStart.sh Filter. Hier legen wir z. B. einen OnJobTaskStart.sh Filter mit Befehl, sed –s 's/specialword/OnJobTaskStart/g', fest, der Befehl verwendet stdin JSON-Eingabedaten, ersetzt Zeichenfolge specialword durch OnJobTaskStart und Ausgabe über Stdout:
Übermitteln Sie dann einen Auftrag, um zu überprüfen, ob der Filter funktioniert:
Problembehandlung beim Fehler bei Ausführungsfiltern
Wenn der Auftrag fehlgeschlagen ist, überprüfen Sie das Nodemanager-Protokoll auf dem jeweiligen Knoten. Das Protokoll gibt exit-Code für den Fehlerausführungsfilter an. Beispiel: In der folgenden Momentaufnahme ist "JobStartFilter" mit Beendigungscode 127 fehlgeschlagen.
Fügen Sie Protokollierungen im Ausführungsfilter hinzu, und geben Sie die Ausgabe an die Dateien.
Verwenden des Ausführungsfilters zum Ausführen eines Auftrags als Domänenbenutzer und Bereitstellen von SMB-Freigaben für unterschiedliche Domänenbenutzer
Im Juni QFE-Release von HPChaben wir den Ausführungsfilter für Linux-Knoten eingeführt (dieses Feature ist nicht öffentlich verfügbar). Der Ausführungsfilter kann aktiviert werden, indem der Ordner mit dem Namen filters im Installationsordner /opt/hpcnodemanagerdes HPC Linux-Knotenmanagers hinzugefügt wird, und Hook-Skripts, die OnJobTaskStart.sh, OnTaskStart.sh oder OnJobEnd.sh im ordner filters benennen. Weitere Informationen zum Ausführungsfilter finden Sie unter HPC Pack Execution Filter für Linux.
In diesem Beispiel erfüllen wir das folgende Szenario:
- HPC-Administrator verfügt über HPC-Cluster mit integrierten Active Directory-Linux-Knoten.
- Um einige Anwendungen zu unterstützen, legen sie den Benutzernamen im angepassten Format fest, z. B. "domain.username" auf den Linux-Knoten über "smb.conf", wenn winbind oder sssd.conf bei Verwendung von SSSD verwendet wird, und möchte damit HPC Aufträge als der richtige Domänenbenutzer auf diesen Linux-Knoten ausführen.
- Für jeden Domänenbenutzer hat der Administrator dedizierte SMB-Freigaben erstellt und wünscht, dass diese Freigaben in den Freigabeordner im Startverzeichnis jedes Benutzers entsprechend eingebunden werden können, und somit können Benutzer Daten nutzen, die sie in der Freigabe gespeichert haben.
Wissen über die Berechtigungssteuerung für Freigaben:
- Informationen zum Festlegen der Berechtigungssteuerung einer SMB-Freigabe in Windows finden Sie unter Verwalten von Berechtigungen für freigegebene Ordner
- Informationen dazu, wie die Berechtigung der SMB-Freigabe auf Linux-Seite gesteuert wird, finden Sie unter
man 8 mountoderman mount.cifs
Konfigurationsschritte:
Richten Sie die SMB-Freigabe wie im beschriebenen Szenario ein, in diesem Beispiel erstellen wir einen Freigabeordner auf server
LN11-RH71-HN1, wobei sieSmbShareDemobenannt wird. Und erstellen Sie dann Unterverzeichnisse im OrdnerSmbShareDemofür verschiedene Domänenbenutzer, z. B. ordnermpiuser1,mpiuser2,mpiuser3für Domänenbenutzerhpclnpr11\mpiuser1,hpclnpr11\mpiuser2,hpclnpr11\mpiuser3und usw. Wir erteilen dem Domänenbenutzerread/writeBerechtigung für den Zugriff auf den Freigabeordner entsprechend, z. B.hpclnpr11\mpiuser1read\writeBerechtigung für Ordnermpiuser1:
Vorbereiten der Ausführungsfilter:
2.1 Erstellen Sie unter dem Linux-Knoten Filterordner:
2.2 Verwenden Sie
chmod 700 /opt/hpcnodemanager/filters, um die Berechtigungen von Ausführungsfiltern einzuschränken, und stellen Sie sicher, dass nur Administratoren (Stamm- oder Sudoers) die Ausführungsfilter anzeigen und ändern können.2.3 Kopieren Sie die Beispielskripts ResolveUserName.py und ResolveUserNameAndDoMount.py (siehe Ende dieses Artikels), und kopieren Sie sie in den Ordner
/opt/hpcnodemanager/filters/.2.4 Erstellen eines OnJobTaskStart-Filters
OnJobTaskStart.shzum Aufrufen des Python-SkriptsResolveUserNameAndDoMount.py:
Das Skript
ResolveUserNameAndDoMount.pyverwendetResolveUserName.pyLogik zum Verfassen des gewünschten Benutzernamens und stellt gleichzeitig die Freigabebenennung//[SmbShareSever]/SmbShareDemo/[UserName]für Nichtadministratorbenutzer im Heimverzeichnis der Benutzer in den Freigabeordner ein, wenn die Freigabe noch nicht bereitgestellt wurde. (Hier[SmbShareSever]ist der Freigabeserver, d. h.LN11-RH71-HN1in diesem Beispiel ist[UserName]der Name des Auftrags, der als Benutzer ausgeführt wird, der angegeben wird, wenn der Auftrag übermittelt wird.)2.5 Ändern Sie die
ResolveUserName.py, und stellen Sie sicher, dass sie den richtigen Benutzernamen verfasst hat:
2.6 Ändern der
ResolveUserNameAndDoMount.pyStellen Sie sicher, dass sie
ResolveUserName.pykorrekt importieren kann, standardmäßig müssen sie sich im selben Ordner befinden.Ersetzen Sie die
[SmbShareSever]durch den SMB-Servernamen in Ihrer Umgebung:
Standardmäßig wird das Verzeichnis mit file_mode
0755und dir_mode0755bereitgestellt, bitte nehmen Sie Änderungen vor, die Ihre Anforderungen erfüllen:
Die Protokollierungseinrichtungen können zur Problembehandlung verwendet werden, da die Kommentare im Skript:
Testen Sie die Ausführungsfilter mit einem HPC-Auftrag:
3.1 Überprüfen Sie den Status der Linux-Knoten, ob die Freigabe für
mpiuser1bereitgestellt wurde, und ob der Bash-Befehl mithilfe von Domänenbenutzern ausgeführt werden kann.
3.2 Auftrag mit Aufgabe
whoamiund Ressource an den Knoten mit Ausführungsfiltersatz auswählen:
3.3 Überprüfen Sie, ob die Ausführung wie erwartet ausgeführt wird und die Freigabe ordnungsgemäß bereitgestellt wird:
Um die Filter für alle Linux-Knoten verfügbar zu machen, kopieren Sie die Filter in die Freigabe, und stellen Sie die Filter für alle Linux-Knoten aus der Freigabe mithilfe von clusrun bereit:
PS > clusrun /nodegroup:LinuxNodes cp -rf <SmbSharePath>/filters /opt/hpcnodemanager/
Skripts als Anhang
ResolveUserName.py
#!/usr/bin/env python # Hpc Execution Filter Sample - Compose Customized Active Directory User Name # Introduction: # When it's in an Active Directly integrated Linux environment, # it's necessary to compose right RunAs user with different settings, # such as: 'winbind seperator' set in /etc/samba/smb.conf for Winbind # or 're_expression' set in /etc/sssd/sssd.conf for SSSD. # to ensure right user is used when HPC run jobs. # # In this case, we compose RunAs user, for example: # composedUserName = "{0}.{1}".format(domainName, userName) when Winbind Seperator set to . delimiter # or In SSSD, when set re_expression = ((?P<domain>.+)\.(?P<name>[^\\\.@]+$)) # # Return codes: # 0 success # 1 incorrect invocation import json import sys def ComposeAdUserName(domainName, userName): """ Examples: composedUserName = "{0}@{1}".format(userName, domainName), when using userName@domainName """ composedUserName = "{0}.{1}".format(domainName, userName) return composedUserName def Main(): """The input is job execution context in json format.""" jsonData = json.loads(sys.stdin.readline()) """Get and compose user name, by default it's in domain\username format.""" composedUserName = jsonData["m_Item3"] runAsUserInfo = composedUserName.split('\\') if len(runAsUserInfo) == 2: domainName = runAsUserInfo[0] userName = runAsUserInfo[1] composedUserName = ComposeAdUserName(domainName, userName) """Set composedUserName.""" jsonData["m_Item3"] = composedUserName """Return the result through stdout""" print json.dumps(jsonData) sys.exit(0) if __name__ == '__main__': Main()ResolveUserNameAndDoMount.py
#!/usr/bin/env python # Hpc Execution Filter Sample - Compose Customized Active Directory User Name and Do Mount For Non-Admin Users # This script reuse ResolveUserName.py to compose right Active Directory user name, # and do mount for Non-Admin users. # # The sample fulfils the following scenario: # Administrators use HPC Linux Support with Active Directory Integrated, # and provide SMB Shares with pattern //SmbShareBasePath/UserName for each Active Directory User to do data movement. # Administrators wish to ensure the shares can be mounted for different users. # In this script, the specific SMB share will be mounted to the share folder in each users' home directory, # with uid and gid set correspondingly, and file_mode and dir_mode both set to 755. # # Please notice this sample script will parse the password of users for mounting, # and be sure this aligns security policies before using it in production environments. # # Return codes: # This script follow command mount's return codes: # 0 success # 1 incorrect invocation or permissions # 2 system error (out of memory, cannot fork, no more loop devices) # 4 internal mount bug # 8 user interrupt # 16 problems writing or locking /etc/mtab # 32 mount failure # 64 some mount succeeded # For more about mount's return codes, please refer man 8 mount. import json import os import pwd import string import subprocess import sys import time import ResolveUserName """Define the constants.""" SmbShareBasePath = "//[SmbShareSever]/SmbShareDemo" def MountSmbShare(smbSharePath, targetPath, domainName, userName, password, uid, gid, fileMode="0755", dirMode="0755"): retCode = 0 if os.path.ismount(targetPath) == False: maxRetry = 3 while(maxRetry > 0): retCode = Run("mount -t cifs {0} {1} -o domain={2},username={3},password='{4}',uid={5},gid={6},file_mode={7},dir_mode={8}".format(smbSharePath, targetPath, domainName, userName, password, uid, gid, fileMode, dirMode)) """Check if succeeded, and skip the case when another process successfully mount the share.""" if retCode == 0 or os.path.ismount(targetPath): retCode = 0 break maxRetry = maxRetry - 1 time.sleep(1) return retCode """Run command facilities.""" if not hasattr(subprocess,'check_output'): def check_output(*popenargs, **kwargs): r"""Backport from subprocess module from python 2.7""" if 'stdout' in kwargs: raise ValueError('stdout argument not allowed, it will be overridden.') process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) output, unused_err = process.communicate() retcode = process.poll() if retcode: cmd = kwargs.get("args") if cmd is None: cmd = popenargs[0] raise subprocess.CalledProcessError(retcode, cmd, output=output) return output # Exception classes used by this module. class CalledProcessError(Exception): def __init__(self, returncode, cmd, output=None): self.returncode = returncode self.cmd = cmd self.output = output def __str__(self): return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) subprocess.check_output=check_output subprocess.CalledProcessError=CalledProcessError def Run(cmd,chk_err=True): retcode,out=RunGetOutput(cmd,chk_err) return retcode def RunGetOutput(cmd,chk_err=True): try: output=subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) except subprocess.CalledProcessError,e : if chk_err : Error('CalledProcessError. Error Code is ' + str(e.returncode) ) Error('CalledProcessError. Command result was ' + (e.output[:-1]).decode('latin-1')) return e.returncode,e.output.decode('latin-1') return 0,output.decode('latin-1') """End of run command facilities.""" """ Logging facilities can be removed from the script. Log can be used for trouble shooting, and remember to comment them out when performance is considered more important. """ LocalTime = time.localtime() ExecutionFilterSampleLogFile = "./ExecutionFilter_ResolveUserAndMount_%04u%02u%02u-%02u%02u%02u.log" % (LocalTime.tm_year, LocalTime.tm_mon, LocalTime.tm_mday, LocalTime.tm_hour, LocalTime.tm_min, LocalTime.tm_sec) def LogWithPrefix(prefix, message): t = time.localtime() t = "%04u/%02u/%02u %02u:%02u:%02u " % (t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec) t += prefix for line in message.split('\n'): line = t + line line = filter(lambda x : x in string.printable, line) try: with open(ExecutionFilterSampleLogFile, "a") as F : F.write(line.encode('ascii','ignore') + "\n") except IOError, e: pass def Log(message): LogWithPrefix("INFO: ", message) def Error(message): LogWithPrefix("ERROR: ", message) def Warn(message): LogWithPrefix("WARNING: ", message) """End of logging facilities.""" def Main(): retCode = 0 """The input is job execution context in json format.""" jsonData = json.loads(sys.stdin.readline()) try: """Get user name, by default it's in domain\username format.""" composedUserName = jsonData["m_Item3"] runAsUserInfo = composedUserName.split('\\') if len(runAsUserInfo) < 2: Error("Illegal input runAsUser: {0}, be sure the input is hpc job context in json format.".format(composedUserName)) sys.exit(1) domainName = runAsUserInfo[0] userName = runAsUserInfo[1] """Resolve right Active Directory user name.""" composedUserName = ResolveUserName.ComposeAdUserName(domainName, userName) """Query if the user is admin, and mount for Non-Admin users.""" isAdmin = "0" try: isAdmin = jsonData["m_Item2"]["environmentVariables"]["CCP_ISADMIN"] except KeyError: pass if isAdmin == "0": """Check whether user exists, touch user's home dir, and get user information.""" retCode = Run("mkhomedir_helper {0}".format(composedUserName)) if retCode != 0: Error("No such user: {0}, or home directory for this user cannot be used or generated properly.".format(composedUserName)) sys.exit(1) pwdInfo = pwd.getpwnam(composedUserName) uid = pwdInfo.pw_uid gid = pwdInfo.pw_gid homeDir = pwdInfo.pw_dir """Get password, please note the risk here.""" password = jsonData["m_Item4"] """Do mount for Non-Admin users.""" smbSharePath = "{0}/{1}".format(SmbShareBasePath, userName) targetPath = "{0}/share".format(homeDir) retCode = Run("mkdir -p {0}".format(targetPath)) if retCode != 0: Error("Cannot find and create mount target path: {0}".format(targetPath)) sys.exit(1) retCode = MountSmbShare(smbSharePath, targetPath, domainName, userName, password, uid, gid) """Set composedUserName.""" jsonData["m_Item3"] = composedUserName except KeyError: """Please check whether the script is used correctly.""" Error("Please check whether the script is used correctly, and ensure it get right format job context json.") retCode = 1 """Return the result through stdout.""" print json.dumps(jsonData) #Log("ExecutionFitler finished with retCode:{0}".format(retCode)) sys.exit(retCode) if __name__ == '__main__': Main()