Maximum Licenses not working

Tagged: 

Viewing 6 posts - 1 through 6 (of 6 total)
  • 14th September 2019 at 11:31 am #21837

    I can’t seem to get the maximum licenses part of the template working. And It’s probably just me screwing up.
    I copied over the below lines from the default nuke template into our custom one and set the number of licenses:
    self.setMaximumLicenses(4)
    self.setLicensesGroup(‘Nuke-licensing’)
    but it’s still being run on all nodes.

    Am I missing something?

    14th September 2019 at 1:19 pm #21841

    Seems fine. Could you post the complete template constructor ?
    Also does it works for you on the stock template ? Are you on 9.0.14 right ?

    14th September 2019 at 1:44 pm #21844

    I haven’t tried it with the stock template yet. I’ll give that a go, and yes we’re on 9.0.14.

    Here’s our custom template (Hope the code inject works):

    
    import os
    import re
    
    import MClientAPI
    import MTemplateAPI
    
    manager = MTemplateAPI.MManager.getUniqueClass()
    
    class STUDIO_nuke_template(MTemplateAPI.MTemplate):
        def __init__(self):
            MTemplateAPI.MTemplate.__init__(self)
            self.setID(1100)
            self.setName('STUDIO_nuke')
            self.setIconFilename('nuke.png')
            self.setDescription('Nuke render')
            self.setMaximumLicenses(4)
            self.setLicensesGroup('Nuke-licensing')
            self.setTemplateLogic(MTemplateAPI.kTemplateMultiframe)
            self.setDefaultPriority(70)
            self.setDefaultPools('2D_NUKE')
            
            ''' Multiframe template specific settings '''
            self.multiframe.setEnableFrameCheck(True)
            self.multiframe.setEnableMovieAssembler(False)
            self.multiframe.setCanProvideFramesMask(True)
            self.multiframe.setSupportsRenderLayerFlag(False)
    
            ''' Submission form items allocation '''
            filePath = MTemplateAPI.MTemplateItemFile('FILEPATH','Nuke script','Specifies the nuke script to render','',0,1,1,'*.nk')
            envPath = MTemplateAPI.MTemplateItemFile('ENVPATH','Environment file','Specifies the environment file to use','',0,1,1,'*.env')
            writeNode = MTemplateAPI.MTemplateItemString('WRITENODE','WriteNode','WriteNode','',0,1,1)
            outputPath = MTemplateAPI.MTemplateItemFolder('OUTPUTPATH','Frames destination','Specifies the frames destination','',0,1,1)
    
            self.addSubmissionItem(filePath)
            self.addSubmissionItem(envPath)
            self.addSubmissionItem(writeNode)
            self.addSubmissionItem(outputPath)
    
            ''' items mapping to Muster default tags '''
            self.addMapping('FILEPATH','job_file')
            self.addMapping('ENVPATH','job_env')
            self.addMapping('WRITENODE','job_writeNode')
            self.addMapping('OUTPUTPATH','output_folder')
            
            ''' Windows support '''
            self.platformWindows.setPlatformEnabled(True)
            self.platformWindows.setEnableErrorCheck(True)
            self.platformWindows.setEnabledByDefault(True)
            self.platformWindows.setFramesFloating(3)
            self.platformWindows.setDetectionLogic(MTemplateAPI.kProcessChild)
            self.platformWindows.setDetectionLogicProcessName('nuke.exe')
            
            applicationPath = MTemplateAPI.MTemplateItemFile('EXEPATH','Nuke executable','Path to Nuke render.exe application batch render','C:\\Program Files\\Nuke11.3v5\\Nuke11.3.exe',0,0,1,'*.exe')
            self.platformWindows.addClientConfigurationItem(applicationPath)
            startingFolderPath = MTemplateAPI.MTemplateItemFolder('SOFTWAREPATH','Starting folder','Specify the starting folder for the nuke','C:\\Program Files\\Nuke11.3v5',0,0,1)
            self.platformWindows.addClientConfigurationItem(startingFolderPath)
    
        ''' virtual functions overrides '''
        def onBuildEnvironment(self, job, chunk, clientTemplatePreferences, existingEnvironment):
            environment = existingEnvironment
            
            envFile = job.attributeGetString(manager.resolveMappingToJob(self.getID(),'ENVPATH'))
            if os.path.exists(envFile):
                FILE = open(envFile, 'r')
                for line in FILE:
                    if '=' in line:
                        envVar = line.rstrip('\n').rstrip('\r').split('=')[0]
                        value = line.rstrip('\n').rstrip('\r').split('=')[1]
                        environment.setValue(envVar, value)
                FILE.close()
    
            return environment
        
        def onBuildCommandLine(self, platform, job, chunk, clientTemplatePreferences,instanceNum):
            renderCmd = ' -F ' + '%.0f' % chunk.getStartFrame() + '-' + '%.0f' % chunk.getEndFrame()
            renderCmd += ' -X \"' + job.attributeGetString(manager.resolveMappingToJob(self.getID(),'WRITENODE')) + '\"'
            renderCmd += ' \"' + job.attributeGetString(manager.resolveMappingToJob(self.getID(),'FILEPATH')) + '\"'
            return renderCmd
            
        def onGetApplicationPath(self,job,chunk,clientTemplatePreferences,pathOut):
            pathOut.setString(clientTemplatePreferences['EXEPATH'])
            return MTemplateAPI.MTemplateError()
            
        def onGetApplicationStartingFolder(self,job,chunk,clientTemplatePreferences,pathOut):
            pathOut.setString(clientTemplatePreferences['SOFTWAREPATH'])
            return MTemplateAPI.MTemplateError()
            
        def onCheckForSubframeAdvancingString(self,job,chunk,line):
            return 0
    
        def onCheckForSubframeProgress(self,job,chunk,line, progressOut):
            return 0
    
        def onCheckForFramesMask(self,job,chunk,line,prefixOut):
            return 0
    		
        def onCheckForFramesMaskForLayer(self,job,chunk,line, prefixOut,layerOut):
            return 0
    
        def onGetFlagForRenderLayers(self,job,layers):
            return ""
    		
        def onCheckLogLine(self,job,chunk,clientTemplatePreferences,line,lineNum,warnings,errors,silencedWarnings,silencedErrors):	
            return MTemplateAPI.MTemplateError()
    		
        def onCheckLog(self,job,chunk,clientTemplatePreferences,log,warnings,errors,silencedWarnings,silencedErrors):
            lines = log.split("\n")
    		
            for idx, val in enumerate(lines):
                marker = manager.checkForLineParsingOverrides(job,chunk,val,idx)
                if marker.getType() == MClientAPI.MTextFileMarker.kFileMarkerError:
                    errors.append(marker)
                elif marker.getType() == MClientAPI.MTextFileMarker.kFileMarkerWarning:
                    warnings.append(marker)
                elif marker.getType() == MClientAPI.MTextFileMarker.kFileMarkerSilenceError:
                    ''' The builtin parser has a skip rule for this line, do not include it in the warnings/errors but in the silenced errors'''
                    silencedErrors.append(marker)
                elif marker.getType() == MClientAPI.MTextFileMarker.kFileMarkerSilenceWarning:
                    ''' The builtin parser has a skip rule for this line, do not include it in the warnings/errors but in the silenced warnings'''
                    silencedWarnings.append(marker)
                else:
                    ''' We have no fixed rule , parse the line according to the template logic '''
                    baseError = -1
                    baseWarning = -1
                    length = -1
                    baseError = val.lower().find('error')
                    baseWarning = val.lower().find('warning')
    				
                    if baseError != -1:
                        length = len(val)-baseError;
                        marker = MClientAPI.MTextFileMarker(MClientAPI.MTextFileMarker.kFileMarkerError,idx,baseError,length)
                        errors.append(marker)
                    if baseWarning != -1:
                        length = len(val)-baseWarning;
                        marker = MClientAPI.MTextFileMarker(MClientAPI.MTextFileMarker.kFileMarkerWarning,idx,baseWarning,length)
                        warnings.append(marker)
    			
            if len(errors) > 0 and len(warnings) > 0:
                return MTemplateAPI.MTemplateError(2,'Errors and warnings reported in the log. Please check the chunk details for a detailed list',MTemplateAPI.MTemplateError.kTemplateErrorTypeError)
            elif len(errors) > 0:
                return MTemplateAPI.MTemplateError(2,'Errors reported in the log. Please check the chunk details for a detailed list',MTemplateAPI.MTemplateError.kTemplateErrorTypeError)
            elif len(warnings) > 0:
                return MTemplateAPI.MTemplateError(1,'Warning reported in the log. Please check the chunk details for a detailed list',MTemplateAPI.MTemplateError.kTemplateErrorTypeWarning)
    	
            return MTemplateAPI.MTemplateError()
    		
        def onCheckExitCode(self,job,chunk,clientTemplatePreferences,exitCode):
            if exitCode != 0:
                return MTemplateAPI.MTemplateError(exitCode, 'Exit code %d different from expected 0 value' % exitCode,MTemplateAPI.MTemplateError.kTemplateErrorTypeWarning)
            return MTemplateAPI.MTemplateError()
    
        def onApplicationFinder(self,moduleRegExp,moduleTag):
            ''' Search nuke '''
            moduleTag.setString('Nuke')
            platform = MClientAPI.GetPlatform()
            moduleRegExp.setString('Nuke\d+\.\dv\d+.*?')
            return MTemplateAPI.kTemplateScanModule
    		
        def onFindApplication(self,basePath,clientTemplatePreferences):
            pass
    		
        def onModuleFound(self,moduleExec,modulePath,clientTemplatePreferences):
            platform = MClientAPI.GetPlatform()
            basePath = modulePath.getString()
            baseModule = moduleExec.getString()
            clientTemplatePreferences['SOFTWAREPATH'] = basePath
            clientTemplatePreferences['EXEPATH'] = os.path.join(basePath,baseModule)
            return 1
            
    ''' Create an instance of the template class and install it into the template manager context '''
    temp = STUDIO_nuke_template()
    manager.installPyTemplate(temp)
    
    14th September 2019 at 3:43 pm #21849

    I tired the stock nuke template and it has the same issue.
    Even though I set the maximum licenses to 4 it still renders on all machines in the pool.

    16th September 2019 at 9:47 am #21930

    We are checking if there’s a regression bug in the current 9.0.14 , I’ll let you know during the day or tomorrow, but I’m suspecting so.

    16th September 2019 at 10:39 am #21933

    I confirm a regression bug we just fixed, we uploaded a new build for 9.0.14, you can just re-download it from the web site (linux and windows installers are fixed, mac and rasp will come later). You need to reinstall the Dispatcher (or instead of doing a full installation, install it on another machine and replace the MDispatcherCore.dll file after stopping the service).

    Thanks for reporting the bug!

Viewing 6 posts - 1 through 6 (of 6 total)

You must be logged in to reply to this topic.