Hi Miguel,

Miguel Couceiro <couce...@isec.pt> writes:

> Hi Loris,
>
> I am interested in the script you mentioned. Could you please post the code?
>
> Best regards,
> Miguel

[snip (23 lines)]

>> We have licenses, such as Intel compiler licenses, which can be used
>> both interactively outside the queuing system and within Slurm jobs.
>>
>> We use a script which parses the output of the FlexLM manager and
>> modifies a reservation in which the licenses are defined.  This is run
>> as a cron job once a minute.  It's a bit of a kludge and obviously won't
>> work well if there is a lot of contention for licenses.
>>
>> I can post the code if anyone is interested.
>>
>> Cheers,
>>
>> Loris

It is almost the first thing I wrote in Python, so beware.  Also the
usual caveats apply: use at your own risk, no warranty implied, I'm not
responsible if the script causes your license server to implode, etc.

The code relies on being able to parse the output of the FlexLM license
server.  If you are using something else, you'll have to adapt the
regular expression used appropriately.  The program has an option to
generate a 'Licenses' entry for slurm.conf.  Users then have to specify
both a license and the appropriate reservation, e.g. 

#SBATCH --licenses=matlab_MATLAB
#SBATCH --reservation=licenses_matlab

The main things to be configured are the paths to the license manager
and to 'scontrol' as well as the paths to the license files.

One thing is missing:  The script should also update the reservation to
move the end time continuously into the future, such that it never
expires. 

Here's the code.  Enjoy.  Improvements/suggestions welcome.

Cheers,

Loris

-------------------------------------------------------------------------------

#!/shared/apps/python/python3.4/bin/python
from subprocess import check_output
import re
import string
import os
import sys
import argparse

parser = argparse.ArgumentParser(description="update licence reservations")
parser.add_argument("-i","--initialise", help="generate line for slurm.conf",
                    action="store_true")
parser.add_argument("-d","--dryrun", help="print action without performing it",
                    action="store_true")
args = parser.parse_args()

total_or_available = 'available'
separator = ':'
if args.initialise:
    total_or_available = 'total'
    separator = '*'

lmstat   = '/local/licenses/matlab/etc/lmstat'
scontrol = '/usr/bin/scontrol'

matlab_license_file = '/local/licenses/matlab/etc/license.dat'
intel_license_file = '/shared/licenses/intel/license_2015-2016.lic'

vendors = {}
vendors['matlab'] = {'prefix':'matlab_',
                     'licence_file': matlab_license_file }
vendors['intel']  = {'prefix':'intel_',
                     'licence_file': intel_license_file}

# Note that licence names may contain hyphens (particularly for Intel products)
re_dict = re.compile(r"""Users\s+of\s+(?P<name>\w+(?:-\w+)*):\s+
                         \(Total\s+of\s+(?P<total>\d+)\s+licenses?\s+issued;\s+
                           
Total\s+of\s+(?P<in_use>\d+)\s+licenses?\s+in\s+use\)""",
                     re.VERBOSE)

re_product = re.compile('User.*', re.MULTILINE)
re_name    = re.compile('Users of (.*?):')
re_error   = re.compile('Error')

for vendor, params in vendors.items():

    cmd = [lmstat, "-a", "-c", params['licence_file']]
    out = check_output(cmd)
    string = str(out,'utf-8')

    licences = []

    for line in re_product.findall(string):

        # Something is wrong with the licence manager or license file
        if re_error.search(line):
            product['name'] = re_name.match(line).group(1)
            product['error'] = True
        # Extract licence data
        else:
            m = re_dict.match(line)
            product = m.groupdict()
            product['error'] = False
        licences.append(product)

    licence_strings_total = []
    licence_strings_available = []

    for licence in licences:

        if not licence['error']:
            slurm_licence_name = params['prefix']
            slurm_licence_name += licence['name']
            licence['available'] = int(licence['total']) - \
                                   int(licence['in_use'])
            licence_strings_total.append(slurm_licence_name + \
                                         separator + \
                                         str(licence['total']))
            if licence['available'] > 0: # Slurm doesn't like 0 licenses
                licence_strings_available.append(slurm_licence_name + \
                                                 separator + \
                                                 str(licence['available']))

    slurm_licence_total_string = ",".join(licence_strings_total)
    slurm_licence_available_string = ",".join(licence_strings_available)
    scontrol_string = scontrol + \
                      ' update reservationname=licenses_' + vendor + \
                      ' licenses=' + slurm_licence_available_string

    if args.initialise:
        print(slurm_licence_total_string)
        continue

    if args.dryrun:
        print(scontrol_string)
        continue

    # Actually update the reservation
    os.system(scontrol_string)

# Strings used for testing
#
#string = 'Users of MATLAB_Distrib_Comp_Engine:  (Total of 16 licenses issued;  
Total of 0 licenses in use)'
#string = 'Users of Wavelet_Toolbox:  (Error: 2 licenses, unsupported by 
licensed server)'

-------------------------------------------------------------------------------


-- 
Dr. Loris Bennett (Mr.)
ZEDAT, Freie Universität Berlin         Email loris.benn...@fu-berlin.de

Reply via email to