Freigeben über


Verwenden des Linux-Ausführungsfilters

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:

  1. 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_Item1 enthält grundlegende Auftrags- und Aufgaben-ID-Informationen.

    • Der Inhalt für m_item2 enthält detailliertere Auftragsinformationen, die beschreiben, wie der Auftrag ausgeführt wird und mit welchen Parametern. Der environmentVariables-Block enthält auch den benutzerdefinierten Environment Variables, der im Auftrag/der Aufgabe definiert wurde:

    Envrs

    • Die Inhalte für m_Item3 und m_Item4 sind der Benutzer und das Kennwort des Runas Benutzers des Auftrags. Bitte achten Sie darauf, wenn Ihr Ausführungsfilter diese Informationen verwendet (insbesondere das Kennwort).
  2. 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
        }
    }
    
  3. 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:

OnJobTaskStart-

Übermitteln Sie dann einen Auftrag, um zu überprüfen, ob der Filter funktioniert:

Newjob-

Newjob-

Viewjob-

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.

Protokoll-

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 mount oder man mount.cifs

Konfigurationsschritte:

  1. Richten Sie die SMB-Freigabe wie im beschriebenen Szenario ein, in diesem Beispiel erstellen wir einen Freigabeordner auf server LN11-RH71-HN1, wobei sie SmbShareDemobenannt wird. Und erstellen Sie dann Unterverzeichnisse im Ordner SmbShareDemo für verschiedene Domänenbenutzer, z. B. ordner mpiuser1, mpiuser2, mpiuser3 für Domänenbenutzer hpclnpr11\mpiuser1, hpclnpr11\mpiuser2, hpclnpr11\mpiuser3 und usw. Wir erteilen dem Domänenbenutzer read/write Berechtigung für den Zugriff auf den Freigabeordner entsprechend, z. B. hpclnpr11\mpiuser1read\write Berechtigung für Ordner mpiuser1:

    Freigaben

  2. Vorbereiten der Ausführungsfilter:

    2.1 Erstellen Sie unter dem Linux-Knoten Filterordner:

    FilterFolder-

    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.sh zum Aufrufen des Python-Skripts ResolveUserNameAndDoMount.py:

    OnJobTaskStart-

    Das Skript ResolveUserNameAndDoMount.py verwendet ResolveUserName.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-HN1 in 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:

    ResolveUserName-

    2.6 Ändern der ResolveUserNameAndDoMount.py

    • Stellen Sie sicher, dass sie ResolveUserName.py korrekt importieren kann, standardmäßig müssen sie sich im selben Ordner befinden.

    • Ersetzen Sie die [SmbShareSever] durch den SMB-Servernamen in Ihrer Umgebung:

      SmbShareSever-

    • Standardmäßig wird das Verzeichnis mit file_mode 0755 und dir_mode 0755bereitgestellt, bitte nehmen Sie Änderungen vor, die Ihre Anforderungen erfüllen:

      MountSmbShare-

    • Die Protokollierungseinrichtungen können zur Problembehandlung verwendet werden, da die Kommentare im Skript:

      LogWithPrefix-

  3. 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:

    SubmitJob-

    SubmitJob-

    3.3 Überprüfen Sie, ob die Ausführung wie erwartet ausgeführt wird und die Freigabe ordnungsgemäß bereitgestellt wird:

    Ergebnis-

    Ergebnis-

  4. 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()