示例#1
0
    def set_business_code_description(self, business_code, description):
        """Modify in DB the description of the Business code given in
           parameter. It raises HPCStatsRuntimeError if the Business code
           is not found in DB.
        """

        business = Business(business_code, description)

        if not business.existing(self.db):
            raise HPCStatsRuntimeError( \
                    "unable to find business code %s in database" \
                      % (business_code))

        logger.info("updating business code %s with new description",
                    business_code)
        business.update(self.db)
示例#2
0
    def set_business_code_description(self, business_code, description):
        """Modify in DB the description of the Business code given in
           parameter. It raises HPCStatsRuntimeError if the Business code
           is not found in DB.
        """

        business = Business(business_code, description)

        if not business.existing(self.db):
            raise HPCStatsRuntimeError( \
                    "unable to find business code %s in database" \
                      % (business_code))

        logger.info("updating business code %s with new description",
                    business_code)
        business.update(self.db)
示例#3
0
    def load(self):
        """Load BusinessCodes from CSV files in businesses attribute. Raise
           HPCStatsSourceError if error in encountered.
        """

        self.businesses = []

        self.check()

        with open(self._business_file, 'r') as csvfile:

            file_reader = csv.reader(csvfile, delimiter=';', quotechar='|')
            for row in file_reader:
                if len(row) != 2:
                    raise HPCStatsSourceError( \
                            "business line format in CSV is invalid")
                code = row[0].strip()
                description = row[1].strip()
                if len(code) == 0:
                    raise HPCStatsSourceError( \
                            "business code in CSV is empty")
                if len(description) == 0:
                    description = None
                business = Business(code, description)
                self.businesses.append(business)
示例#4
0
    def test_update_exists(self):
        """ProjectImporterCSV.update() works when business code exists
        """

        business1 = Business('code1', 'business description 1')

        MockPg2.PG_REQS['existing_business'].set_assoc(
            params=(business1.code, ), result=[['code1']])

        self.importer.businesses = [business1]
        self.importer.update()
示例#5
0
    def test_update_exists_with_mock(self, mock_update):
        """ProjectImporterCSV.update() call Business.update() when business
           code exists
        """
        business1 = Business('code1', 'business description 1')

        MockPg2.PG_REQS['existing_business'].set_assoc(
            params=(business1.code, ), result=[['code1']])

        self.importer.businesses = [business1]
        self.importer.update()
        mock_update.assert_called_with(self.db)
示例#6
0
    def load_cluster(self, cluster):
        """Connect to cluster Slurm database to extract business codes from
           jobs wckeys. Raises HPCStatsSourceError in case of error.
        """

        self.log.debug("loading business codes from %s slurm database",
                       cluster)

        self.connect_db(cluster)

        if not len(self.clusters_db[cluster]['partitions']):
            partitions_clause = ''
        else:
            partitions_clause = \
                "WHERE job.partition IN (%s)" % \
                ','.join(['%s'] * len(self.clusters_db[cluster]['partitions']))

        req = """
                SELECT DISTINCT(wckey)
                  FROM %s_job_table job
                  %s
              """ % (self.clusters_db[cluster]['prefix'], partitions_clause)

        params = tuple(self.clusters_db[cluster]['partitions'])
        self.cur.execute(req, params)

        while (1):
            row = self.cur.fetchone()
            if row == None:
                break

            wckey = row[0]

            if wckey == '':
                continue
            else:
                wckey_items = wckey.split(':')
                if len(wckey_items) != 2:
                    if wckey not in self.invalid_wckeys:
                        self.invalid_wckeys.append(wckey)
                        self.log.warn(Errors.E_B0001,
                                      "format of wckey %s is not valid", wckey)
                    continue
                else:
                    business_code = wckey_items[1]
                    business = Business(code=business_code, description=None)

                # check for duplicate project
                if not self.find(business):
                    self.businesses.append(business)
示例#7
0
    def __init__(self, db, config, cluster_name):

        self._db = db
        self._cluster_name = cluster_name

        business_section = self._cluster_name + "/business"
        self._business_file = config.get(business_section, "file")

        if not os.path.isfile(self._business_file):
            logging.error("business file %s does not exist", self._business_file)
            raise RuntimeError

        #In first delete all entries in business table and his dependances 
        logging.debug("Delete all business entries in db")
        delete_contexts_with_business(self._db)
        delete_business(self._db)
        self._db.commit()

        b_file = open(self._business_file, 'r')
        # savepoint is used to considere exceptions and commit only at the end
        db.get_cur().execute("SAVEPOINT my_savepoint;")
        with b_file as csvfile:
            file_reader = csv.reader(csvfile, delimiter=';', quotechar='|')
            for row in file_reader:
                code = Business( key = row[0],
                                 description = row[1])
                try:
                    if not code.already_exist(self._db):
                        code.save(self._db)
                        if not code.get_description():
                            logging.debug("add new business entry with key : %s, without description", code.get_key())
                        else:
                            logging.debug("add new business entry with key : %s, and description : %s", \
                                           code.get_key(), \
                                           code.get_description())
                        db.get_cur().execute("SAVEPOINT my_savepoint;")
                    else :
                        logging.debug("code %s not added, already exist", code.get_key())
                except psycopg2.DataError:
                    logging.error("impossible to add BUSINESS entry in database : (%s) du to encoding error", row)
                    db.get_cur().execute("ROLLBACK TO SAVEPOINT my_savepoint;")
                    pass
        self._db.commit()
        b_file.close()
示例#8
0
    def get_jobs_after_batchid(self, batchid, window_size=0):
        """Fill the jobs attribute with the list of Jobs found in Slurm DB
           whose id_job is over or equals to the batchid in parameter.
           Returns the last found batch_id.
        """

        self.jobs = []

        if window_size:
            limit = "LIMIT %d" % (window_size)
        else:
            limit = ''

        last_batch_id = -1

        old_schema = self._is_old_schema()
        if old_schema is True:
            cpu_field = 'cpus_alloc'
        else:
            cpu_field = 'tres_alloc'

        if not len(self.partitions):
            partitions_clause = ''
        else:
            partitions_clause = "AND job.partition IN (%s)" % \
                                ','.join(['%s'] * len(self.partitions))

        req = """
                SELECT job_db_inx,
                       id_job,
                       id_user,
                       id_group,
                       time_submit,
                       time_start,
                       time_end,
                       timelimit,
                       nodes_alloc,
                       %s,
                       job.partition,
                       qos.name AS qos,
                       job.account,
                       state,
                       nodelist,
                       assoc.user,
                       job_name,
                       wckey
                  FROM %s_job_table job,
                       %s_assoc_table assoc,
                       qos_table qos
                 WHERE job_db_inx >= %%s
                   %s
                   AND assoc.id_assoc = job.id_assoc
                   AND qos.id = job.id_qos
              ORDER BY job_db_inx %s
              """ % (cpu_field, self.prefix, self.prefix, partitions_clause,
                     limit)
        params = (batchid, ) + tuple(self.partitions)
        self.cur.execute(req, params)
        while (1):
            row = self.cur.fetchone()
            if row == None:
                break

            self.nb_loaded_jobs += 1

            batch_id = last_batch_id = row[0]
            sched_id = row[1]

            submission_t = row[4]
            if submission_t == 0:
                submission = None
            else:
                submission = datetime.fromtimestamp(submission_t)

            start_t = row[5]
            if start_t == 0:
                start = None
            else:
                start = datetime.fromtimestamp(start_t)

            end_t = row[6]
            if end_t == 0:
                end = None
            else:
                end = datetime.fromtimestamp(end_t)

            # Some jobs in Slurm DBD have an end but no start. Typically, this
            # concernes the jobs that have been cancelled before starting. For
            # these jobs, we set the start equal to the end.
            if start is None and end is not None:
                start = end

            wall_t = row[7]
            if wall_t == 0:
                walltime = None
            elif wall_t >= 2147483648:
                walltime = "-1"
            else:
                walltime = str(wall_t)

            name = row[16]
            if old_schema is True:
                nbcpu = row[9]
            else:
                nbcpu = extract_tres_cpu(row[9])
                if nbcpu == -1:
                    raise HPCStatsSourceError( \
                            "unable to extract cpus_alloc from job tres")

            state = JobImporterSlurm.get_job_state_from_slurm_state(row[13])

            nodelist = row[14]
            if nodelist == "(null)" or nodelist == "None assigned":
                nodelist = None

            partition = self.job_partition(sched_id, row[10], nodelist)
            qos = row[11]
            queue = "%s-%s" % (partition, qos)
            job_acct = row[12]

            login = row[15]

            searched_user = User(login, None, None, None)
            searched_account = Account(searched_user, self.cluster, None, None,
                                       None, None)
            account = self.app.users.find_account(searched_account)
            if account is None:
                msg = "account %s not found in loaded accounts" \
                        % (login)
                if self.strict_job_account_binding == True:
                    raise HPCStatsSourceError(msg)
                elif login not in self.unknown_accounts:
                    self.unknown_accounts.append(login)
                    self.log.warn(Errors.E_J0001, msg)
                self.nb_excluded_jobs += 1
                continue
            user = self.app.users.find_user(searched_user)
            if user is None:
                msg = "user %s not found in loaded users" % (login)
                raise HPCStatsSourceError(msg)
            job_department = user.department

            wckey = row[17]

            # empty wckey must be considered as None
            if wckey == '':
                wckey = None

            if wckey is None:
                project = None
                business = None
            else:
                wckey_items = wckey.split(':')
                if len(wckey_items) != 2:
                    msg = "format of wckey %s is not valid" % (wckey)
                    if self.strict_job_wckey_format == True:
                        raise HPCStatsSourceError(msg)
                    elif wckey not in self.invalid_wckeys:
                        self.invalid_wckeys.append(wckey)
                        self.log.warn(Errors.E_J0002, msg)
                    project = None
                    business = None
                else:
                    project_code = wckey_items[0]
                    searched_project = Project(None, project_code, None)
                    project = self.app.projects.find_project(searched_project)
                    if project is None:
                        msg = "project %s not found in loaded projects" \
                                % (project_code)
                        if self.strict_job_project_binding == True:
                            raise HPCStatsSourceError(msg)
                        elif project_code not in self.unknown_projects:
                            self.unknown_projects.append(project_code)
                            self.log.warn(Errors.E_J0003, msg)

                    business_code = wckey_items[1]
                    searched_business = Business(business_code, None)
                    business = self.app.business.find(searched_business)

                    if business is None:
                        msg = "business code %s not found in loaded " \
                              "business codes" % (business_code)
                        if self.strict_job_businesscode_binding == True:
                            raise HPCStatsSourceError(msg)
                        elif business_code not in self.unknown_businesses:
                            self.unknown_businesses.append(business_code)
                            self.log.warn(Errors.E_J0004, msg)

            job = Job(account, project, business, sched_id, str(batch_id),
                      name, nbcpu, state, queue, job_acct, job_department,
                      submission, start, end, walltime)
            self.jobs.append(job)

            if nodelist is not None:
                self.create_runs(nodelist, job)

        return last_batch_id
示例#9
0
    def __init__(self, db, config, cluster_name):

        self._db = db
        self._cluster_name = cluster_name

        context_section = self._cluster_name + "/context"
        self._context_file = config.get(context_section, "file")

        if not os.path.isfile(self._context_file):
            logging.error("context file %s does not exist", self._context_file)
            raise RuntimeError

        # delete all contexts entries in databases
        logging.debug("Delete all context entries in db")
        delete_contexts(self._db)
        self._db.commit()

        p_file = open(self._context_file, 'r')
        # save point is used to considere exception and commit in database only at the end
        db.get_cur().execute("SAVEPOINT my_savepoint;")
        with p_file as csvfile:
            file_reader = csv.reader(csvfile, delimiter=',', quotechar='|')
            for row in file_reader:
                 logging.debug("update projects and business codes for user : %s", row[0].lower())
                 # a new context is set in database for all projects attached AND for all business attached.
                 # new line is set with a project referance OR a business referance.
                 if row[6]:
                     for pareo in re.split('\|',row[6]):
                         project = Project()
                         try:
                             project.project_from_pareo(self._db, pareo)
                             context = Context(login = row[0].lower(),
                                               job = None,
                                               project = project.get_id(),
                                               business = None)
                             try:
                                 context.save(self._db)
                                 logging.debug("add context : %s", context)
                                 #self._db.commit()
                                 db.get_cur().execute("SAVEPOINT my_savepoint;")
                             except psycopg2.DataError:
                                 logging.error("impossible to add CONTEXT entry in database : (%s), du to encoding error", row)
                                 db.get_cur().execute("ROLLBACK TO SAVEPOINT my_savepoint;")
                                 pass
                             except psycopg2.IntegrityError:
                                 logging.error("impossible to add CONTEXT entry in database : (%s), du to relations error", row)
                                 db.get_cur().execute("ROLLBACK TO SAVEPOINT my_savepoint;")
                                 pass
                         except:
                             logging.error("context rejected. Project %s does not exist", pareo)
                             db.get_cur().execute("ROLLBACK TO SAVEPOINT my_savepoint;")
                             pass
                 if row[7]:
                     for code in re.split('\|',row[7]):
                         business = Business()
                         try:
                             business.business_from_key(self._db, code)
                             context = Context(login = row[0].lower(),
                                               job = None,
                                               project = None,
                                               business = business.get_id())
                             try:
                                 context.save(self._db)
                                 logging.debug("add context : %s", context)
                                 #self._db.commit()
                                 db.get_cur().execute("SAVEPOINT my_savepoint;")
                             except psycopg2.DataError:
                                 logging.error("impossible to add CONTEXT entry in database : (%s), du to encoding error", row)
                                 db.get_cur().execute("ROLLBACK TO SAVEPOINT my_savepoint;")
                                 pass
                             except psycopg2.IntegrityError:
                                 logging.error("impossible to add CONTEXT entry in database : (%s), du to relations error", row)
                                 db.get_cur().execute("ROLLBACK TO SAVEPOINT my_savepoint;")
                                 pass
                         except:
                             logging.error("context rejected. Business %s does not exist", code) 
                             db.get_cur().execute("ROLLBACK TO SAVEPOINT my_savepoint;")
                             pass
                 if not row[6] and not row[7]:
                     logging.error("line : %s rejected - not code or project associate", row)
        self._db.commit()
        p_file.close()
示例#10
0
 def test_update_not_exists(self):
     """ProjectImporterCSV.update() works when business code does not exist
     """
     business1 = Business('code1', 'business description 1')
     self.importer.businesses = [business1]
     self.importer.update()