some limit improvements

This commit is contained in:
Evgenii Alekseev 2017-02-26 05:00:48 +03:00
parent 5e9b2ad190
commit c2b92cd212
16 changed files with 686 additions and 385 deletions

View File

@ -30,6 +30,7 @@
#include "QueuedDatabase.h" #include "QueuedDatabase.h"
#include "QueuedDebug.h" #include "QueuedDebug.h"
#include "QueuedEnums.h" #include "QueuedEnums.h"
#include "QueuedLimits.h"
#include "QueuedProcess.h" #include "QueuedProcess.h"
#include "QueuedProcessManager.h" #include "QueuedProcessManager.h"
#include "QueuedReportManager.h" #include "QueuedReportManager.h"

View File

@ -26,6 +26,8 @@
#include <QObject> #include <QObject>
#include "QueuedLimits.h"
class QueuedAdvancedSettings; class QueuedAdvancedSettings;
class QueuedDatabase; class QueuedDatabase;
@ -52,16 +54,65 @@ public:
* @brief QueuedCore class destructor * @brief QueuedCore class destructor
*/ */
virtual ~QueuedCore(); virtual ~QueuedCore();
/**
* @brief add new task
* @param _command command line
* @param _arguments command arguments
* @param _workingDirectory working directory
* @param _nice nice level
* @param _userId task owner user ID
* @param _limits task defined limits
* @return true on successfully addition
*/
bool addTask(const QString &_command, const QStringList &_arguments,
const QString &_workingDirectory, const unsigned int _nice,
const long long _userId, const QueuedLimits::Limits &_limits);
/**
* @brief add new user
* @param _name user name
* @param _email user email
* @param _password user password
* @param _permissions user permissions
* @param _limits user limits
* @return true on successfully addition
*/
bool addUser(const QString &_name, const QString &_email,
const QString &_password, const unsigned int _permissions,
const QueuedLimits::Limits &_limits);
/** /**
* @brief deinit subclasses * @brief deinit subclasses
*/ */
void deinit(); void deinit();
/**
* @brief edit user
* @param _id user ID to edit
* @param _userData user data to edit
* @remark ref
* @return
*/
bool editUser(const long long _id, const QVariantHash &_userData);
/** /**
* @brief init subclasses * @brief init subclasses
* @param _configuration path to configuration file * @param _configuration path to configuration file
*/ */
void init(const QString &_configuration); void init(const QString &_configuration);
private slots:
/**
* @brief update process time
* @param _id task id
* @param _startTime task start time or empty
* @param _endTime task end time or empty
*/
void updateTaskTime(const long long _id, const QDateTime &_startTime,
const QDateTime &_endTime);
/**
* @brief update user login time
* @param _id user ID
* @param _time user login time
*/
void updateUserLoginTime(const long long _id, const QDateTime &_time);
private: private:
/** /**
* @brief pointer to advanced settings object * @brief pointer to advanced settings object
@ -87,6 +138,11 @@ private:
* @brief pointer to user manager * @brief pointer to user manager
*/ */
QueuedUserManager *m_users = nullptr; QueuedUserManager *m_users = nullptr;
// additional properties
/**
* @brief connection list
*/
QList<QMetaObject::Connection> m_connections;
}; };

View File

@ -50,13 +50,6 @@ public:
* @brief QueuedDatabase class destructor * @brief QueuedDatabase class destructor
*/ */
virtual ~QueuedDatabase(); virtual ~QueuedDatabase();
/**
* @brief add record to database
* @param _table table name
* @param _value value to insert
* @return index of inserted record or -1 if no insertion
*/
long long add(const QString &_table, const QVariantHash &_value);
/** /**
* @brief check and create database * @brief check and create database
*/ */
@ -82,15 +75,6 @@ public:
* @return variant map from table * @return variant map from table
*/ */
QVariantHash get(const QString &_table, const long long _id); QVariantHash get(const QString &_table, const long long _id);
/**
* @brief modify record in table
* @param _table table name
* @param _id id for search
* @param _value value to update
* @return true on successfully modification
*/
bool modify(const QString &_table, const long long _id,
const QVariantHash &_value);
/** /**
* @brief open database * @brief open database
* @param _hostname hostname to connect, may be empty * @param _hostname hostname to connect, may be empty
@ -107,6 +91,24 @@ public:
*/ */
QString path() const; QString path() const;
public slots:
/**
* @brief add record to database
* @param _table table name
* @param _value value to insert
* @return index of inserted record or -1 if no insertion
*/
long long add(const QString &_table, const QVariantHash &_value);
/**
* @brief modify record in table
* @param _table table name
* @param _id id for search
* @param _value value to update
* @return true on successfully modification
*/
bool modify(const QString &_table, const long long _id,
const QVariantHash &_value);
private: private:
/** /**
* @brief database * @brief database

View File

@ -96,6 +96,7 @@ const QueuedDBSchema DBSchema = {
{"nice", {"nice", "INT", QVariant::UInt}}, {"nice", {"nice", "INT", QVariant::UInt}},
{"uid", {"uid", "INT", QVariant::UInt}}, {"uid", {"uid", "INT", QVariant::UInt}},
{"gid", {"gid", "INT", QVariant::UInt}}, {"gid", {"gid", "INT", QVariant::UInt}},
{"limits", {"limits", "TEXT", QVariant::String}},
{"startTime", {"startTime", "INT", QVariant::LongLong}}, {"startTime", {"startTime", "INT", QVariant::LongLong}},
{"endTime", {"endTime", "INT", QVariant::LongLong}}}}, {"endTime", {"endTime", "INT", QVariant::LongLong}}}},
{TOKENS_TABLE, {TOKENS_TABLE,
@ -112,11 +113,7 @@ const QueuedDBSchema DBSchema = {
{"passwordSHA512", {"passwordSHA512", "TEXT", QVariant::String}}, {"passwordSHA512", {"passwordSHA512", "TEXT", QVariant::String}},
{"email", {"email", "TEXT", QVariant::String}}, {"email", {"email", "TEXT", QVariant::String}},
{"lastLogin", {"lastLogin", "TEXT", QVariant::String}}, {"lastLogin", {"lastLogin", "TEXT", QVariant::String}},
{"cpu", {"cpu", "INT", QVariant::LongLong}}, {"limits", {"limits", "TEXT", QVariant::String}},
{"gpu", {"gpu", "INT", QVariant::LongLong}},
{"memory", {"memory", "INT", QVariant::LongLong}},
{"gpumemory", {"gpumemory", "INT", QVariant::LongLong}},
{"storage", {"storage", "INT", QVariant::LongLong}},
{"permissions", {"permissions", "INT", QVariant::UInt}}}}}; {"permissions", {"permissions", "INT", QVariant::UInt}}}}};
}; };

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2016 Evgeniy Alekseev
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
*
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
/**
* @file QueuedLimits.h
* Header of Queued library
* @author Evgeniy Alekseev
* @copyright MIT
* @bug https://github.com/arcan1s/queued/issues
*/
#ifndef QUEUEDLIMITS_H
#define QUEUEDLIMITS_H
#include <QString>
/**
* @defgroup QueuedLimits
* @brief Queued limits
*/
namespace QueuedLimits
{
/**
* @ingroup QueuedLimits
* @struct Limits
* @var cpu
* limit by CPU
* @var gpu
* limit by GPU
* @var memory
* limit by memory
* @var gpumemory
* limit by GPU memory
* @var storage
* limit by storage
* @var valid
* is this permissions default generated or not
*/
struct Limits {
long long cpu;
long long gpu;
long long memory;
long long gpumemory;
long long storage;
bool valid;
// structure methods
/**
* @brief limits to string conversion
* @return string representation of limits
*/
QString toString() const
{
return QString("%1\x01%2\x01%3\x01%4\x01%5")
.arg(cpu)
.arg(gpu)
.arg(memory)
.arg(gpumemory)
.arg(storage);
};
/**
* @brief default structure constructor
*/
Limits()
: cpu(0)
, gpu(0)
, memory(0)
, gpumemory(0)
, storage(0)
, valid(false){};
/**
* @brief structure constructor from string representation
* @param _stringLimits limits string representation
*/
Limits(const QString &_stringLimits)
{
QStringList limits = _stringLimits.split(QChar('\x01'));
while (limits.count() < 4)
limits.append(QString("0"));
cpu = limits.at(0).toLongLong();
gpu = limits.at(1).toLongLong();
memory = limits.at(2).toLongLong();
gpumemory = limits.at(3).toLongLong();
storage = limits.at(4).toLongLong();
valid = true;
};
};
/**
* @ingroup QueuedLimits
* @brief convert QString memory value to integer
* @param _value value to convert
* @param _status conversion status
* @return converted integer
*/
long long convertMemory(QString _value, bool *_status);
/**
* @ingroup QueuedLimits
* @brief compare two limits
* @param _first first limit
* @param _second second limit
* @return true if first limit is less than second
*/
bool limitCompare(const long long _first, const long long _second);
/**
* @ingroup QueuedLimits
* @brief get minimal limits from given
* @param _task task defined limits
* @param _user user defined limit
* @param _default default limits if anu
* @return minimal limits from given
*/
Limits minimalLimits(const Limits &_task, const Limits &_user,
const Limits &_default);
};
#endif /* QUEUEDLIMITS_H */

View File

@ -26,9 +26,8 @@
#include <QDateTime> #include <QDateTime>
#include <QProcess> #include <QProcess>
#include <QVariant>
#include "QueuedEnums.h" #include "QueuedLimits.h"
/** /**
@ -62,6 +61,8 @@ public:
* process end time * process end time
* @var user * @var user
* task owner ID * task owner ID
* @var limits
* task limits
*/ */
typedef struct { typedef struct {
QString command; QString command;
@ -73,6 +74,7 @@ public:
QDateTime startTime; QDateTime startTime;
QDateTime endTime; QDateTime endTime;
long long user; long long user;
QueuedLimits::Limits limits;
} QueuedProcessDefinitions; } QueuedProcessDefinitions;
/** /**
@ -98,18 +100,6 @@ public:
* @return generated name of process * @return generated name of process
*/ */
QString name() const; QString name() const;
/**
* @brief remove limit
* @param _limitType limit type
*/
virtual void removeLimit(const QueuedEnums::LimitType _limitType);
/**
* @brief set limit
* @param _limitType limit type
* @param _value limit value
*/
virtual void setLimit(const QueuedEnums::LimitType _limitType,
const QVariant &_value = QVariant());
/** /**
* @brief equal operator implementation * @brief equal operator implementation
* @param _other other object * @param _other other object
@ -143,17 +133,6 @@ private:
* @brief index of process * @brief index of process
*/ */
long long m_index = -1; long long m_index = -1;
/**
* @brief limits array
*/
QHash<QueuedEnums::LimitType, long long> m_limits;
/**
* @brief convert QString memory value to integer
* @param _value value to convert
* @param _status conversion status
* @return converted integer
*/
long long convertMemory(QString _value, bool *_status) const;
}; };

View File

@ -74,23 +74,25 @@ public:
virtual ~QueuedProcessManager(); virtual ~QueuedProcessManager();
/** /**
* @brief add task * @brief add task
* @param _properties task properties from database
* @param _index task index * @param _index task index
* @return pointer to created task
*/
QueuedProcess *add(const QVariantHash &_properties, const long long _index);
/**
* @brief add task
* @param _definitions process definitions * @param _definitions process definitions
* @param _index task index
* @return pointer to created task * @return pointer to created task
*/ */
QueuedProcess * QueuedProcess *
add(const long long _index, add(const QueuedProcess::QueuedProcessDefinitions _definitions,
const QueuedProcess::QueuedProcessDefinitions _definitions); const long long _index);
/** /**
* @brief add tasks from database * @brief add tasks from database
* @param _processes database stored tasks * @param _processes database stored tasks
*/ */
void add(const QList<QVariantHash> &_processes); void loadProcesses(const QList<QVariantHash> &_processes);
/**
* @brief default action on exit
* @return default action from possible ones
*/
OnExitAction onExit() const;
/** /**
* @brief task * @brief task
* @param _index task index * @param _index task index
@ -112,6 +114,11 @@ public:
* @param _index task index * @param _index task index
*/ */
void stop(const long long _index); void stop(const long long _index);
/**
* @brief default action on exit
* @return default action from possible ones
*/
OnExitAction onExit() const;
signals: signals:
/** /**
@ -119,13 +126,13 @@ signals:
* @param _index task index * @param _index task index
* @param _time task start time * @param _time task start time
*/ */
void taskStartTimeReceived(const long long _index, const QDateTime _time); void taskStartTimeReceived(const long long _index, const QDateTime &_time);
/** /**
* @brief signal which will be called on task end * @brief signal which will be called on task end
* @param _index task index * @param _index task index
* @param _time task stop time * @param _time task stop time
*/ */
void taskStopTimeReceived(const long long _index, const QDateTime _time); void taskStopTimeReceived(const long long _index, const QDateTime &_time);
private slots: private slots:
/** /**

View File

@ -28,6 +28,7 @@
#include <QVariant> #include <QVariant>
#include "QueuedEnums.h" #include "QueuedEnums.h"
#include "QueuedLimits.h"
/** /**
@ -45,16 +46,8 @@ class QueuedUser : public QObject
Q_PROPERTY(unsigned int permissions READ permissions WRITE setPermissions Q_PROPERTY(unsigned int permissions READ permissions WRITE setPermissions
NOTIFY userUpdated) NOTIFY userUpdated)
// limits // limits
Q_PROPERTY( Q_PROPERTY(QueuedLimits::Limits limits READ limits WRITE setLimits NOTIFY
long long cpuLimit READ cpuLimit WRITE setCpuLimit NOTIFY userUpdated) userUpdated)
Q_PROPERTY(
long long gpuLimit READ gpuLimit WRITE setGpuLimit NOTIFY userUpdated)
Q_PROPERTY(long long memoryLimit READ memoryLimit WRITE setMemoryLimit
NOTIFY userUpdated)
Q_PROPERTY(long long gpumemoryLimit READ gpumemoryLimit WRITE
setGpumemoryLimit NOTIFY userUpdated)
Q_PROPERTY(long long storageLimit READ storageLimit WRITE setStorageLimit
NOTIFY userUpdated)
public: public:
/** /**
@ -68,27 +61,15 @@ public:
* password hash, may be empty * password hash, may be empty
* @var permissions * @var permissions
* user permissions * user permissions
* @var cpuLimit * @var limits
* user limit by CPU * user defined limits
* @var gpuLimit
* user limit by GPU
* @var memoryLimit
* user limit by memory
* @var gpumemoryLimit
* user limit by GPU memory
* @var storageLimit
* user limit by storage
*/ */
typedef struct { typedef struct {
QString name; QString name;
QString email; QString email;
QString passwordSHA512; QString passwordSHA512;
unsigned int permissions; unsigned int permissions;
long long cpuLimit; QueuedLimits::Limits limits;
long long gpuLimit;
long long memoryLimit;
long long gpumemoryLimit;
long long storageLimit;
} QueuedUserDefinitions; } QueuedUserDefinitions;
/** /**
@ -124,6 +105,11 @@ public:
* @return true if user has permission otherwise return false * @return true if user has permission otherwise return false
*/ */
bool hasPermission(const QueuedEnums::Permission _permission); bool hasPermission(const QueuedEnums::Permission _permission);
/**
* @brief get UID and GID from user ID
* @return pair of {uid, gid}
*/
QPair<unsigned int, unsigned int> ids();
/** /**
* @brief check if password is valid * @brief check if password is valid
* @param _password password as string * @param _password password as string
@ -165,30 +151,10 @@ public:
unsigned int permissions() const; unsigned int permissions() const;
// permissions // permissions
/** /**
* @brief cpu limit * @brief user limits
* @return cpu limit in cores * @return user limits
*/ */
long long cpuLimit() const; QueuedLimits::Limits limits() const;
/**
* @brief gpu limit
* @return gpu limit in cores
*/
long long gpuLimit() const;
/**
* @brief memory limit
* @return memory limit in bytes
*/
long long memoryLimit() const;
/**
* @brief GPU memory limit
* @return GPU memory limit in bytes
*/
long long gpumemoryLimit() const;
/**
* @brief storage limit
* @return storage limit in bytes
*/
long long storageLimit() const;
// main properties // main properties
/** /**
* @brief set user email * @brief set user email
@ -212,30 +178,10 @@ public:
void setPermissions(const unsigned int _permissions); void setPermissions(const unsigned int _permissions);
// permissions // permissions
/** /**
* @brief set cpu limit * @brief set limits
* @param _cpuLimit new cpu limit in cores * @param _limit new user limits
*/ */
void setCpuLimit(const long long _cpuLimit); void setLimits(const QueuedLimits::Limits &_limits);
/**
* @brief set gpu limit
* @param _gpuLimit new gpu limit in cores
*/
void setGpuLimit(const long long _gpuLimit);
/**
* @brief set memory limit
* @param _memoryLimit new memory limit in bytes
*/
void setMemoryLimit(const long long _memoryLimit);
/**
* @brief set GPU memory limit
* @param _gpumemoryLimit new GPU memory limit in bytes
*/
void setGpumemoryLimit(const long long _gpumemoryLimit);
/**
* @brief set storage limit
* @param _storageLimit new storage limit in bytes
*/
void setStorageLimit(const long long _storageLimit);
/** /**
* @brief equal operator implementation * @brief equal operator implementation
* @param _other other object * @param _other other object

View File

@ -52,6 +52,13 @@ public:
* @brief QueuedUserManager class destructor * @brief QueuedUserManager class destructor
*/ */
virtual ~QueuedUserManager(); virtual ~QueuedUserManager();
/**
* @brief add user
* @param _properties user properties from database
* @param _id user ID
* @return pointer to created user
*/
QueuedUser *add(const QVariantHash &_properties, const long long _id);
/** /**
* @brief add user * @brief add user
* @param _definitions user definitions * @param _definitions user definitions
@ -76,6 +83,12 @@ public:
*/ */
bool authorize(const QString &_user, const QString &_token, bool authorize(const QString &_user, const QString &_token,
const QueuedEnums::Permission _service); const QueuedEnums::Permission _service);
/**
* @brief get UID and GID from user ID
* @param _id user id
* @return pair of {uid, gid}
*/
QPair<unsigned int, unsigned int> ids(const long long _id);
/** /**
* @brief load tokens * @brief load tokens
* @param _tokens tokens list from database * @param _tokens tokens list from database
@ -86,6 +99,12 @@ public:
* @param _users users list from database * @param _users users list from database
*/ */
void loadUsers(const QList<QVariantHash> &_users); void loadUsers(const QList<QVariantHash> &_users);
/**
* @brief user by ID
* @param _id user id for search
* @return user by id or nullptr if no user found
*/
QueuedUser *user(const long long _id);
/** /**
* @brief user by name * @brief user by name
* @param _name user name for search * @param _name user name for search
@ -104,6 +123,14 @@ public:
*/ */
void setTokenExpiration(const long long &_expiry); void setTokenExpiration(const long long &_expiry);
signals:
/**
* @brief signal which emits on each user successfully login
* @param _id user ID
* @param _time user login time
*/
void userLoggedIn(const long long _id, const QDateTime &_time);
private: private:
/** /**
* @brief token expiration in days * @brief token expiration in days

View File

@ -50,11 +50,89 @@ QueuedCore::~QueuedCore()
} }
/**
* @addTask
*/
bool QueuedCore::addTask(const QString &_command, const QStringList &_arguments,
const QString &_workingDirectory,
const unsigned int _nice, const long long _userId,
const QueuedLimits::Limits &_limits)
{
qCDebug(LOG_LIB) << "Add task" << _command << "with arguments" << _arguments
<< "from user" << _userId;
auto ids = m_users->ids(_userId);
auto taskLimits = QueuedLimits::minimalLimits(
_limits, m_users->user(_userId)->limits(),
QueuedLimits::Limits(
m_advancedSettings->get(QString("DefaultLimits")).toString()));
QVariantHash properties
= {{"userId", _userId}, {"command", _command},
{"arguments", _arguments}, {"workDirectory", _workingDirectory},
{"nice", _nice}, {"uid", ids.first},
{"gid", ids.second}, {"limits", taskLimits.toString()}};
auto id = m_database->add(QueuedDB::TASKS_TABLE, properties);
if (id == -1) {
qCWarning(LOG_LIB) << "Could not add task" << _command;
return false;
}
m_processes->add(properties, id);
return true;
}
/**
* @fn addUser
*/
bool QueuedCore::addUser(const QString &_name, const QString &_email,
const QString &_password,
const unsigned int _permissions,
const QueuedLimits::Limits &_limits)
{
qCDebug(LOG_LIB) << "Add user" << _name << "with email" << _email
<< "and permissions" << _permissions;
QVariantHash properties
= {{"name", _name},
{"passwordSHA512", QueuedUser::hashFromPassword(_password)},
{"email", _email},
{"permissions", _permissions},
{"limits", _limits.toString()}};
auto id = m_database->add(QueuedDB::USERS_TABLE, properties);
if (id == -1) {
qCWarning(LOG_LIB) << "Could not add user" << _name;
return false;
}
m_users->add(properties, id);
return true;
}
/** /**
* @fn deinit * @fn deinit
*/ */
void QueuedCore::deinit() void QueuedCore::deinit()
{ {
// clear connections first
for (auto &connection : m_connections)
disconnect(connection);
m_connections.clear();
// delete objects now
if (m_reports)
delete m_reports;
if (m_processes)
delete m_processes;
if (m_users)
delete m_users;
if (m_database)
delete m_database;
if (m_settings)
delete m_settings;
if (m_advancedSettings)
delete m_advancedSettings;
} }
@ -92,10 +170,61 @@ void QueuedCore::init(const QString &_configuration)
m_users->setTokenExpiration(expiry); m_users->setTokenExpiration(expiry);
m_users->loadTokens(m_database->get(QueuedDB::TOKENS_TABLE)); m_users->loadTokens(m_database->get(QueuedDB::TOKENS_TABLE));
m_users->loadUsers(m_database->get(QueuedDB::USERS_TABLE)); m_users->loadUsers(m_database->get(QueuedDB::USERS_TABLE));
m_connections += connect(
m_users, SIGNAL(userLoggedIn(const long long, const QDateTime &)), this,
SLOT(updateUserLoginTime(const long long, const QDateTime &)));
// and processes finally // and processes finally
auto onExitAction = static_cast<QueuedProcessManager::OnExitAction>( auto onExitAction = static_cast<QueuedProcessManager::OnExitAction>(
m_advancedSettings->get(QString("OnExitAction")).toInt()); m_advancedSettings->get(QString("OnExitAction")).toInt());
m_processes = new QueuedProcessManager(this, onExitAction); m_processes = new QueuedProcessManager(this, onExitAction);
m_processes->add(m_database->get(QueuedDB::TASKS_TABLE)); m_processes->loadProcesses(m_database->get(QueuedDB::TASKS_TABLE));
m_connections
+= connect(m_processes, &QueuedProcessManager::taskStartTimeReceived,
[this](const long long _index, const QDateTime &_time) {
return updateTaskTime(_index, _time, QDateTime());
});
m_connections
+= connect(m_processes, &QueuedProcessManager::taskStopTimeReceived,
[this](const long long _index, const QDateTime &_time) {
return updateTaskTime(_index, QDateTime(), _time);
});
}
/**
* @fn updateTaskTime
*/
void QueuedCore::updateTaskTime(const long long _id,
const QDateTime &_startTime,
const QDateTime &_endTime)
{
qCDebug(LOG_LIB) << "Update task" << _id << "time to" << _startTime
<< _endTime;
QVariantHash record;
if (_startTime.isValid())
record[QString("startTime")] = _startTime.toString(Qt::ISODate);
if (_endTime.isValid())
record[QString("endTime")] = _endTime.toString(Qt::ISODate);
bool status = m_database->modify(QueuedDB::TASKS_TABLE, _id, record);
if (!status)
qCWarning(LOG_LIB) << "Could not modify task record" << _id;
}
/**
* @fn updateUserLoginTime
*/
void QueuedCore::updateUserLoginTime(const long long _id,
const QDateTime &_time)
{
qCDebug(LOG_LIB) << "Update user" << _id << "with login time" << _time;
QVariantHash record = {{"lastLogin", _time.toString(Qt::ISODate)}};
bool status = m_database->modify(QueuedDB::USERS_TABLE, _id, record);
if (!status)
qCWarning(LOG_LIB) << "Could not modify user record" << _id;
} }

View File

@ -51,31 +51,8 @@ QueuedDatabase::QueuedDatabase(QObject *parent, const QString path,
QueuedDatabase::~QueuedDatabase() QueuedDatabase::~QueuedDatabase()
{ {
qCDebug(LOG_LIB) << __PRETTY_FUNCTION__; qCDebug(LOG_LIB) << __PRETTY_FUNCTION__;
}
m_database.close();
/**
* @fn add
*/
long long QueuedDatabase::add(const QString &_table, const QVariantHash &_value)
{
qCDebug(LOG_LIB) << "Add record" << _value << "to table" << _table;
auto payload = getQueryPayload(_table, _value);
// build query
QSqlQuery query
= m_database.exec(QString("INSERT INTO %1 (%2) VALUES (%3)")
.arg(_table)
.arg(payload.first.join(QChar(',')))
.arg(payload.second.join(QChar(','))));
QSqlError error = query.lastError();
if (error.isValid()) {
qCCritical(LOG_LIB) << "Could not add record" << _value << "to table"
<< _table << "message" << error.text();
return -1;
}
return lastInsertionId(_table);
} }
@ -181,37 +158,6 @@ QVariantHash QueuedDatabase::get(const QString &_table, const long long _id)
} }
/**
* @fn modify
*/
bool QueuedDatabase::modify(const QString &_table, const long long _id,
const QVariantHash &_value)
{
qCDebug(LOG_LIB) << "Modify record" << _id << "in table" << _table
<< "with value" << _value;
auto payload = getQueryPayload(_table, _value);
QStringList stringPayload;
for (int i = 0; i < payload.first.count(); i++)
stringPayload.append(QString("%1='%2'")
.arg(payload.first.at(i))
.arg(payload.second.at(i)));
// build query
QSqlQuery query = m_database.exec(QString("UPDATE %1 SET %2 WHERE _id=%3")
.arg(_table)
.arg(stringPayload.join(QChar(',')))
.arg(_id));
QSqlError error = query.lastError();
if (error.isValid()) {
qCCritical(LOG_LIB) << "Could not add record" << _value << "to table"
<< _table << "message" << error.text();
return false;
}
return true;
}
/** /**
* @fn open * @fn open
*/ */
@ -243,6 +189,62 @@ QString QueuedDatabase::path() const
} }
/**
* @fn add
*/
long long QueuedDatabase::add(const QString &_table, const QVariantHash &_value)
{
qCDebug(LOG_LIB) << "Add record" << _value << "to table" << _table;
auto payload = getQueryPayload(_table, _value);
// build query
QSqlQuery query
= m_database.exec(QString("INSERT INTO %1 (%2) VALUES (%3)")
.arg(_table)
.arg(payload.first.join(QChar(',')))
.arg(payload.second.join(QChar(','))));
QSqlError error = query.lastError();
if (error.isValid()) {
qCCritical(LOG_LIB) << "Could not add record" << _value << "to table"
<< _table << "message" << error.text();
return -1;
}
return lastInsertionId(_table);
}
/**
* @fn modify
*/
bool QueuedDatabase::modify(const QString &_table, const long long _id,
const QVariantHash &_value)
{
qCDebug(LOG_LIB) << "Modify record" << _id << "in table" << _table
<< "with value" << _value;
auto payload = getQueryPayload(_table, _value);
QStringList stringPayload;
for (int i = 0; i < payload.first.count(); i++)
stringPayload.append(QString("%1='%2'")
.arg(payload.first.at(i))
.arg(payload.second.at(i)));
// build query
QSqlQuery query = m_database.exec(QString("UPDATE %1 SET %2 WHERE _id=%3")
.arg(_table)
.arg(stringPayload.join(QChar(',')))
.arg(_id));
QSqlError error = query.lastError();
if (error.isValid()) {
qCCritical(LOG_LIB) << "Could not modify record" << _value << "in table"
<< _table << "message" << error.text();
return false;
}
return true;
}
/** /**
* @fn createSchema * @fn createSchema
*/ */

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2016 Evgeniy Alekseev
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
*
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
/**
* @file QueuedLimits.cpp
* Source code of queued library
* @author Evgeniy Alekseev
* @copyright GPLv3
* @bug https://github.com/arcan1s/queued/issues
*/
#include "queued/Queued.h"
/**
* @fn convertMemory
*/
long long QueuedLimits::convertMemory(QString _value, bool *_status)
{
long long intValue;
if (_value.endsWith(QString("K")))
intValue = _value.remove(QString("K")).toLongLong(_status) * 1024;
else if (_value.endsWith(QString("M")))
intValue
= _value.remove(QString("M")).toLongLong(_status) * 1024 * 1024;
else if (_value.endsWith(QString("G")))
intValue = _value.remove(QString("G")).toLongLong(_status) * 1024 * 1024
* 1024;
else
intValue = _value.toInt(_status);
return intValue;
}
/**
* @fn limitCompare
*/
bool QueuedLimits::limitCompare(const long long _first, const long long _second)
{
if (_first == 0)
return false;
else if (_second == 0)
return true;
else
return _first < _second;
}
/**
* @fn minimalLimits
*/
QueuedLimits::Limits
QueuedLimits::minimalLimits(const QueuedLimits::Limits &_task,
const QueuedLimits::Limits &_user,
const QueuedLimits::Limits &_default)
{
QueuedLimits::Limits limits;
limits.cpu = std::min({_task.cpu, _user.cpu, _default.cpu}, &limitCompare);
limits.gpu = std::min({_task.gpu, _user.gpu, _default.gpu}, &limitCompare);
limits.memory = std::min({_task.memory, _user.memory, _default.memory},
&limitCompare);
limits.gpumemory = std::min(
{_task.gpumemory, _user.gpumemory, _default.gpumemory}, &limitCompare);
limits.storage = std::min({_task.storage, _user.storage, _default.storage},
&limitCompare);
return limits;
}

View File

@ -23,9 +23,12 @@
#include "queued/Queued.h" #include "queued/Queued.h"
#include <unistd.h>
#include <queued/Queued.h> #include <queued/Queued.h>
extern "C" {
#include <unistd.h>
}
/** /**
* @class QueuedProcess * @class QueuedProcess
@ -75,41 +78,6 @@ QString QueuedProcess::name() const
} }
/**
* @fn removeLimit
*/
void QueuedProcess::removeLimit(const QueuedEnums::LimitType _limitType)
{
qCDebug(LOG_LIB) << "Remove limit" << static_cast<int>(_limitType);
m_limits.remove(_limitType);
}
/**
* @fn setLimit
*/
void QueuedProcess::setLimit(const QueuedEnums::LimitType _limitType,
const QVariant &_value)
{
qCDebug(LOG_LIB) << "Set limit" << static_cast<int>(_limitType) << "to"
<< _value;
if (!_value.isValid())
return removeLimit(_limitType);
bool status = false;
long long intValue = _value.type() == QVariant::String
? convertMemory(_value.toString(), &status)
: _value.toLongLong(&status);
if (!status)
removeLimit(_limitType);
else
m_limits[_limitType] = intValue;
}
/** /**
* @fn operator== * @fn operator==
*/ */
@ -142,33 +110,9 @@ void QueuedProcess::run()
/** /**
* @fn setEndTime * @fn setEndTime
*/ */
void QueuedProcess::setEndTime(const QDateTime &_time) void QueuedProcess::setEndTime(const QDateTime &_time)
{ {
qCDebug(LOG_LIB) << "Set end time to" << _time; qCDebug(LOG_LIB) << "Set end time to" << _time;
m_definitions.endTime = _time; m_definitions.endTime = _time;
} }
/**
* @fn convertMemory
*/
long long QueuedProcess::convertMemory(QString _value, bool *_status) const
{
qCDebug(LOG_LIB) << "Convert memory value" << _value;
long long intValue;
if (_value.endsWith(QString("K")))
intValue = _value.remove(QString("K")).toLongLong(_status) * 1024;
else if (_value.endsWith(QString("M")))
intValue
= _value.remove(QString("M")).toLongLong(_status) * 1024 * 1024;
else if (_value.endsWith(QString("G")))
intValue = _value.remove(QString("G")).toLongLong(_status) * 1024 * 1024
* 1024;
else
intValue = _value.toInt(_status);
qCInfo(LOG_LIB) << "Converted value" << intValue;
return intValue;
}

View File

@ -50,12 +50,44 @@ QueuedProcessManager::~QueuedProcessManager()
} }
/**
* @fn add
*/
QueuedProcess *QueuedProcessManager::add(const QVariantHash &_properties,
const long long _index)
{
qCDebug(LOG_LIB) << "Add new process" << _properties << "with index"
<< _index;
QueuedProcess::QueuedProcessDefinitions defs;
// parameters
defs.command = _properties[QString("command")].toString();
defs.arguments
= _properties[QString("arguments")].toString().split(QChar('\x01'));
defs.workingDirectory = _properties[QString("workDirectory")].toString();
defs.nice = _properties[QString("nice")].toUInt();
defs.limits
= QueuedLimits::Limits(_properties[QString("limits")].toString());
// user data
defs.uid = _properties[QString("uid")].toUInt();
defs.gid = _properties[QString("gid")].toUInt();
defs.user = _properties[QString("user")].toLongLong();
// metadata
defs.startTime = QDateTime::fromString(
_properties[QString("startTime")].toString(), Qt::ISODate);
defs.endTime = QDateTime::fromString(
_properties[QString("endTime")].toString(), Qt::ISODate);
return add(defs, _index);
}
/** /**
* @fn add * @fn add
*/ */
QueuedProcess *QueuedProcessManager::add( QueuedProcess *QueuedProcessManager::add(
const long long _index, const QueuedProcess::QueuedProcessDefinitions _definitions,
const QueuedProcess::QueuedProcessDefinitions _definitions) const long long _index)
{ {
qCDebug(LOG_LIB) << "Add new process" << _definitions.command qCDebug(LOG_LIB) << "Add new process" << _definitions.command
<< "with index" << _index; << "with index" << _index;
@ -78,41 +110,14 @@ QueuedProcess *QueuedProcessManager::add(
/** /**
* @fn add * @fn loadProcesses
*/ */
void QueuedProcessManager::add(const QList<QVariantHash> &_processes) void QueuedProcessManager::loadProcesses(const QList<QVariantHash> &_processes)
{ {
qCDebug(LOG_LIB) << "Add tasks from" << _processes; qCDebug(LOG_LIB) << "Add tasks from" << _processes;
for (auto &pr : _processes) { for (auto &processData : _processes)
QueuedProcess::QueuedProcessDefinitions defs; add(processData, processData[QString("_id")].toLongLong());
// parameters
defs.command = pr[QString("command")].toString();
defs.arguments
= pr[QString("arguments")].toString().split(QChar('\x01'));
defs.workingDirectory = pr[QString("workDirectory")].toString();
defs.nice = pr[QString("nice")].toUInt();
// user data
defs.uid = pr[QString("uid")].toUInt();
defs.gid = pr[QString("gid")].toUInt();
defs.user = pr[QString("user")].toLongLong();
// metadata
defs.startTime = QDateTime::fromString(
pr[QString("startTime")].toString(), Qt::ISODate);
defs.endTime = QDateTime::fromString(pr[QString("endTime")].toString(),
Qt::ISODate);
add(pr[QString("_id")].toLongLong(), defs);
}
}
/**
* @fn onExit
*/
QueuedProcessManager::OnExitAction QueuedProcessManager::onExit() const
{
return m_onExit;
} }
@ -150,7 +155,7 @@ void QueuedProcessManager::remove(const long long _index)
auto connection = m_connections.take(_index); auto connection = m_connections.take(_index);
disconnect(connection); disconnect(connection);
switch (m_onExit) { switch (onExit()) {
case OnExitAction::Kill: case OnExitAction::Kill:
pr->kill(); pr->kill();
break; break;
@ -177,7 +182,7 @@ void QueuedProcessManager::stop(const long long _index)
return; return;
} }
switch (m_onExit) { switch (onExit()) {
case OnExitAction::Kill: case OnExitAction::Kill:
pr->kill(); pr->kill();
break; break;
@ -189,6 +194,15 @@ void QueuedProcessManager::stop(const long long _index)
} }
/**
* @fn onExit
*/
QueuedProcessManager::OnExitAction QueuedProcessManager::onExit() const
{
return m_onExit;
}
/** /**
* @fn taskFinished * @fn taskFinished
*/ */

View File

@ -25,6 +25,11 @@
#include <QCryptographicHash> #include <QCryptographicHash>
extern "C" {
#include <pwd.h>
#include <sys/types.h>
}
/** /**
* @class QueuedUser * @class QueuedUser
@ -94,6 +99,24 @@ bool QueuedUser::hasPermission(const QueuedEnums::Permission _permission)
} }
/**
* @fn ids
*/
QPair<unsigned int, unsigned int> QueuedUser::ids()
{
QPair<unsigned int, unsigned int> system = {1, 1};
auto pwd = getpwnam(name().toLocal8Bit().constData());
if (!pwd) {
qCWarning(LOG_LIB) << "No user found by name" << name();
return system;
}
system = {pwd->pw_uid, pwd->pw_gid};
return system;
}
/** /**
* @fn isPasswordValid * @fn isPasswordValid
*/ */
@ -164,47 +187,11 @@ unsigned int QueuedUser::permissions() const
/** /**
* @fn cpuLimit * @fn limits
*/ */
long long QueuedUser::cpuLimit() const QueuedLimits::Limits QueuedUser::limits() const
{ {
return m_definitions.cpuLimit; return m_definitions.limits;
}
/**
* @fn gpuLimit
*/
long long QueuedUser::gpuLimit() const
{
return m_definitions.gpuLimit;
}
/**
* @fn memoryLimit
*/
long long QueuedUser::memoryLimit() const
{
return m_definitions.memoryLimit;
}
/**
* @fn gpumemoryLimit
*/
long long QueuedUser::gpumemoryLimit() const
{
return m_definitions.gpumemoryLimit;
}
/**
* @fn storageLimit
*/
long long QueuedUser::storageLimit() const
{
return m_definitions.storageLimit;
} }
@ -253,57 +240,13 @@ void QueuedUser::setPermissions(const unsigned int _permissions)
/** /**
* @fn setCpuLimit * @fn setLimits
*/ */
void QueuedUser::setCpuLimit(const long long _cpuLimit) void QueuedUser::setLimits(const QueuedLimits::Limits &_limits)
{ {
qCDebug(LOG_LIB) << "New user cpu limit" << _cpuLimit; qCDebug(LOG_LIB) << "New user limits" << _limits.toString();
m_definitions.cpuLimit = _cpuLimit; m_definitions.limits = _limits;
}
/**
* @fn setGpuLimit
*/
void QueuedUser::setGpuLimit(const long long _gpuLimit)
{
qCDebug(LOG_LIB) << "New user gpu limit" << _gpuLimit;
m_definitions.gpuLimit = _gpuLimit;
}
/**
* @fn setMemoryLimit
*/
void QueuedUser::setMemoryLimit(const long long _memoryLimit)
{
qCDebug(LOG_LIB) << "New user memory limit" << _memoryLimit;
m_definitions.memoryLimit = _memoryLimit;
}
/**
* @fn setGpumemoryLimit
*/
void QueuedUser::setGpumemoryLimit(const long long _gpumemoryLimit)
{
qCDebug(LOG_LIB) << "New user gpu memory limit" << _gpumemoryLimit;
m_definitions.gpumemoryLimit = _gpumemoryLimit;
}
/**
* @fn setStorageLimit
*/
void QueuedUser::setStorageLimit(const long long _storageLimit)
{
qCDebug(LOG_LIB) << "New user storage limit" << _storageLimit;
m_definitions.storageLimit = _storageLimit;
} }

View File

@ -53,6 +53,26 @@ QueuedUserManager::~QueuedUserManager()
} }
/**
* @fn add
*/
QueuedUser *QueuedUserManager::add(const QVariantHash &_properties,
const long long _id)
{
qCDebug(LOG_LIB) << "Add user" << _properties << "with ID" << _id;
QueuedUser::QueuedUserDefinitions defs;
defs.name = _properties[QString("name")].toString();
defs.email = _properties[QString("email")].toString();
defs.passwordSHA512 = _properties[QString("passwordSHA512")].toString();
defs.permissions = _properties[QString("permissions")].toUInt();
defs.limits
= QueuedLimits::Limits(_properties[QString("limits")].toString());
return add(defs, _id);
}
/** /**
* @fn add * @fn add
*/ */
@ -82,19 +102,21 @@ QString QueuedUserManager::authorize(const QString &_user,
{ {
qCDebug(LOG_LIB) << "Authorize user" << _user; qCDebug(LOG_LIB) << "Authorize user" << _user;
if (!m_users.contains(_user)) { auto userObj = user(_user);
if (!userObj) {
qCInfo(LOG_LIB) << "No user found" << _user; qCInfo(LOG_LIB) << "No user found" << _user;
return QString(); return QString();
} }
bool status = m_users[_user]->isPasswordValid(_password); bool status = userObj->isPasswordValid(_password);
if (!status) { if (!status) {
qCInfo(LOG_LIB) << "User password invalid for" << _user; qCInfo(LOG_LIB) << "User password invalid for" << _user;
return QString(); return QString();
} }
QDateTime expiry auto time = QDateTime::currentDateTimeUtc();
= QDateTime::currentDateTimeUtc().addDays(tokenExpiration()); QDateTime expiry = time.addDays(tokenExpiration());
emit(userLoggedIn(userObj->index(), time));
return m_tokens->registerToken(expiry); return m_tokens->registerToken(expiry);
} }
@ -123,6 +145,23 @@ bool QueuedUserManager::authorize(const QString &_user, const QString &_token,
} }
/**
* @fn ids
*/
QPair<unsigned int, unsigned int> QueuedUserManager::ids(const long long _id)
{
qCDebug(LOG_LIB) << "Get ids for user" << _id;
auto userObj = user(_id);
if (!userObj) {
qCWarning(LOG_LIB) << "No user found for ID" << _id;
return {1, 1};
}
return userObj->ids();
}
/** /**
* @fn loadTokens * @fn loadTokens
*/ */
@ -142,21 +181,25 @@ void QueuedUserManager::loadUsers(const QList<QVariantHash> &_users)
qCDebug(LOG_LIB) << "Set users from" << _users; qCDebug(LOG_LIB) << "Set users from" << _users;
// load now // load now
for (auto &userdata : _users) { for (auto &userData : _users)
QueuedUser::QueuedUserDefinitions defs; add(userData, userData[QString("_id")].toLongLong());
defs.name = userdata[QString("name")].toString(); }
defs.email = userdata[QString("email")].toString();
defs.passwordSHA512 = userdata[QString("passwordSHA512")].toString();
defs.permissions = userdata[QString("permissions")].toUInt();
// limits
defs.cpuLimit = userdata[QString("cpuLimit")].toLongLong();
defs.gpuLimit = userdata[QString("gpuLimit")].toLongLong();
defs.memoryLimit = userdata[QString("memoryLimit")].toLongLong();
defs.gpumemoryLimit = userdata[QString("gpumemoryLimit")].toLongLong();
defs.storageLimit = userdata[QString("storageLimit")].toLongLong();
add(defs, userdata[QString("_id")].toLongLong());
/**
* @fn user
*/
QueuedUser *QueuedUserManager::user(const long long _id)
{
qCDebug(LOG_LIB) << "Look for user" << _id;
for (auto &userObj : m_users.values()) {
if (userObj->index() != _id)
continue;
return userObj;
} }
return nullptr;
} }
@ -167,7 +210,7 @@ QueuedUser *QueuedUserManager::user(const QString &_name)
{ {
qCDebug(LOG_LIB) << "Look for user" << _name; qCDebug(LOG_LIB) << "Look for user" << _name;
return m_users.contains(_name) ? m_users[_name] : nullptr; return m_users.value(_name, nullptr);
} }