mirror of
https://github.com/outbackdingo/sysadm.git
synced 2026-01-27 18:20:23 +00:00
Merge branch 'master' of https://github.com/pcbsd/sysadm
This commit is contained in:
@@ -20,7 +20,7 @@ Every beadm class request contains the following parameters:
|
||||
| namespace | sysadm | |
|
||||
| | | |
|
||||
+---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+
|
||||
| action | | supported actions include "listbes", "renamebe" |
|
||||
| action | | supported actions include "listbes", "renamebe", "activatebe", "createbe" |
|
||||
| | | |
|
||||
+---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
@@ -137,4 +137,105 @@ The "renamebe" action renames the specified boot environment. When using this ac
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
|
||||
.. index:: activatebe, beadm
|
||||
|
||||
.. _Activate Boot Environment:
|
||||
|
||||
Activate Boot Environment
|
||||
=========================
|
||||
|
||||
The "activatebe" action activates the specified boot environment (target) so that it will be the default at next boot.
|
||||
|
||||
|
||||
**REST Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
PUT /sysadm/beadm
|
||||
{
|
||||
"target" : "bootthingy",
|
||||
"action" : "activatebe"
|
||||
}
|
||||
|
||||
**WebSocket Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"name" : "beadm",
|
||||
"args" : {
|
||||
"action" : "activatebe",
|
||||
"target" : "bootthingy"
|
||||
},
|
||||
"namespace" : "sysadm",
|
||||
"id" : "fooid"
|
||||
}
|
||||
|
||||
**Response**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"args": {
|
||||
"activatebe": {
|
||||
"target": "bootthingy"
|
||||
}
|
||||
},
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
|
||||
.. index:: createbe, beadm
|
||||
|
||||
.. _Create Boot Environment:
|
||||
|
||||
Create Boot Environment
|
||||
=======================
|
||||
|
||||
The "create" action creates a new boot environment. Specify the name of the boot environment as the "newbe". By default, this action clones the active boot environment.
|
||||
To specify another, inactive boot environment, also include "clonefrom" to specify which boot environment to clone from.
|
||||
|
||||
**REST Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
PUT /sysadm/beadm
|
||||
{
|
||||
"action" : "createbe",
|
||||
"newbe" : "red",
|
||||
"clonefrom" : "green"
|
||||
}
|
||||
|
||||
**WebSocket Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"id" : "fooid",
|
||||
"args" : {
|
||||
"newbe" : "red",
|
||||
"clonefrom" : "green",
|
||||
"action" : "createbe"
|
||||
},
|
||||
"namespace" : "sysadm",
|
||||
"name" : "beadm"
|
||||
}
|
||||
|
||||
**Response**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"args": {
|
||||
"createbe": {
|
||||
"clonefrom": "green",
|
||||
"newbe": "red"
|
||||
}
|
||||
},
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
@@ -21,7 +21,8 @@ Every iocage class request contains the following parameters:
|
||||
| | | |
|
||||
+---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+
|
||||
| action | | supported actions include "getdefaultsettings", "listjails", "getjailsettings", "startjail", "stopjail", |
|
||||
| | | "capjail", "cleanjails", "cleanreleases", "cleantemplates", "cleanall", "activatepool", and "deactivatepool" |
|
||||
| | | "capjail", "clonejail", "cleanjails", "cleanreleases", "cleantemplates", "cleanall", "activatepool", and |
|
||||
| | | "deactivatepool" |
|
||||
| | | |
|
||||
+---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
@@ -839,6 +840,108 @@ the jail.
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
|
||||
.. index:: clonejail, iocage
|
||||
|
||||
.. _Clone a Jail:
|
||||
|
||||
Clone a Jail
|
||||
============
|
||||
|
||||
The "clonejail" action clones the specified "jail". By default, the clone will inherit that jail's properties. Use "props" to specify any properties that should differ. All available
|
||||
properties are described in `iocage(8) <https://github.com/iocage/iocage/blob/master/iocage.8.txt>`_.
|
||||
|
||||
In this example, the "tag" property is specified so that the new jail has a different name than the jail it was cloned from.
|
||||
|
||||
**REST Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
PUT /sysadm/iocage
|
||||
{
|
||||
"props" : "tag=newtest",
|
||||
"jail" : "test",
|
||||
"action" : "clonejail"
|
||||
}
|
||||
|
||||
**WebSocket Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"namespace" : "sysadm",
|
||||
"name" : "iocage",
|
||||
"args" : {
|
||||
"action" : "clonejail",
|
||||
"jail" : "test",
|
||||
"props" : "tag=newtest"
|
||||
},
|
||||
"id" : "fooid"
|
||||
}
|
||||
|
||||
**Response**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"args": {
|
||||
"clonejail": {
|
||||
"jail": "test",
|
||||
"props": "tag=newtest",
|
||||
"success": {
|
||||
"Successfully created": " 5e1fe97e-cfba-11e5-8209-d05099728dbf (newtest)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
|
||||
In this example, no properties are specified so iocage populates its own values and the props returned in the response is empty:
|
||||
|
||||
**REST Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
PUT /sysadm/iocage
|
||||
{
|
||||
"action" : "clonejail",
|
||||
"jail" : "test"
|
||||
}
|
||||
|
||||
**WebSocket Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"args" : {
|
||||
"jail" : "test",
|
||||
"action" : "clonejail"
|
||||
},
|
||||
"name" : "iocage",
|
||||
"namespace" : "sysadm",
|
||||
"id" : "fooid"
|
||||
}
|
||||
|
||||
**Response**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"args": {
|
||||
"clonejail": {
|
||||
"jail": "test",
|
||||
"props": "",
|
||||
"success": {
|
||||
"Successfully created": " 89e78032-cfba-11e5-8209-d05099728dbf (2016-02-09@23"
|
||||
}
|
||||
}
|
||||
},
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
|
||||
.. index:: cleanjails, iocage
|
||||
|
||||
.. _Clean Jails:
|
||||
|
||||
@@ -20,7 +20,8 @@ Every iohyve class request contains the following parameters:
|
||||
| namespace | sysadm | |
|
||||
| | | |
|
||||
+---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+
|
||||
| action | | supported actions include "listvms", "fetchiso", "renameiso", "rmiso" |
|
||||
| action | | supported actions include "listvms", "fetchiso", "renameiso", "rmiso", "setup", "issetup", "create", "install", |
|
||||
| | | "start", "stop" |
|
||||
| | | |
|
||||
+---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
@@ -244,4 +245,300 @@ The "rmiso" action is used to to remove an existing ISO file from disk. Specify
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
|
||||
.. index:: setup, iohyve
|
||||
|
||||
.. _Setup iohyve:
|
||||
|
||||
Setup iohyve
|
||||
============
|
||||
|
||||
The "setup" action performs the initial setup of iohyve. It is mandatory to specify the FreeBSD device name of the "nic" and the ZFS "pool" to use.
|
||||
|
||||
**REST Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
PUT /sysadm/iohyve
|
||||
{
|
||||
"nic" : "re0",
|
||||
"pool" : "tank",
|
||||
"action" : "setup"
|
||||
}
|
||||
|
||||
**WebSocket Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"id" : "fooid",
|
||||
"name" : "iohyve",
|
||||
"args" : {
|
||||
"pool" : "tank",
|
||||
"nic" : "re0",
|
||||
"action" : "setup"
|
||||
},
|
||||
"namespace" : "sysadm"
|
||||
}
|
||||
|
||||
**Response**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"args": {
|
||||
"setup": {
|
||||
"nic": "re0",
|
||||
"pool": "tank"
|
||||
}
|
||||
},
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
|
||||
.. index:: issetup, iohyve
|
||||
|
||||
.. _Determine iohyve Setup:
|
||||
|
||||
Determine iohyve Setup
|
||||
======================
|
||||
|
||||
The "issetup" action queries if iohyve has been setup and returns either "true" or "false".
|
||||
|
||||
**REST Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
PUT /sysadm/iohyve
|
||||
{
|
||||
"action" : "issetup"
|
||||
}
|
||||
|
||||
**WebSocket Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"id" : "fooid",
|
||||
"namespace" : "sysadm",
|
||||
"args" : {
|
||||
"action" : "issetup"
|
||||
},
|
||||
"name" : "iohyve"
|
||||
}
|
||||
|
||||
**Response**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"args": {
|
||||
"issetup": {
|
||||
"setup": "true"
|
||||
}
|
||||
},
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
|
||||
.. index:: create, iohyve
|
||||
|
||||
.. _Create Guest:
|
||||
|
||||
Create Guest
|
||||
============
|
||||
|
||||
The "create" action creates a new iohyve guest of the specified "name" and "size".
|
||||
|
||||
**REST Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
PUT /sysadm/iohyve
|
||||
{
|
||||
"action" : "create",
|
||||
"name" : "bsdguest",
|
||||
"size" : "10G"
|
||||
}
|
||||
|
||||
**WebSocket Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"name" : "iohyve",
|
||||
"namespace" : "sysadm",
|
||||
"id" : "fooid",
|
||||
"args" : {
|
||||
"name" : "bsdguest",
|
||||
"action" : "create",
|
||||
"size" : "10G"
|
||||
}
|
||||
}
|
||||
|
||||
**Response**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"args": {
|
||||
"create": {
|
||||
"name": "bsdguest",
|
||||
"size": "10G"
|
||||
}
|
||||
},
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
|
||||
.. index:: install, iohyve
|
||||
|
||||
.. _Install Guest:
|
||||
|
||||
Install Guest
|
||||
=============
|
||||
|
||||
The "install" action starts the iohyve installation of the specified guest from the specified ISO. This action only boots the VM with the ISO; to do the actual installation,
|
||||
run :command:`iohyve console <name>` from the system.
|
||||
|
||||
**REST Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
PUT /sysadm/iohyve
|
||||
{
|
||||
"name" : "bsdguest",
|
||||
"iso" : "FreeBSD-10.2-RELEASE-amd64-disc1.iso",
|
||||
"action" : "install"
|
||||
}
|
||||
|
||||
**WebSocket Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"namespace" : "sysadm",
|
||||
"name" : "iohyve",
|
||||
"id" : "fooid",
|
||||
"args" : {
|
||||
"action" : "install",
|
||||
"iso" : "FreeBSD-10.2-RELEASE-amd64-disc1.iso",
|
||||
"name" : "bsdguest"
|
||||
}
|
||||
}
|
||||
|
||||
**Response**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"args": {
|
||||
"install": {
|
||||
"iso": "FreeBSD-10.2-RELEASE-amd64-disc1.iso",
|
||||
"name": "bsdguest"
|
||||
}
|
||||
},
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
|
||||
.. index:: start, iohyve
|
||||
|
||||
.. _Start VM:
|
||||
|
||||
Start VM
|
||||
========
|
||||
|
||||
The "start" action starts the specified VM.
|
||||
|
||||
**REST Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
PUT /sysadm/iohyve
|
||||
{
|
||||
"action" : "start",
|
||||
"name" : "bsdguest"
|
||||
}
|
||||
|
||||
**WebSocket Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"name" : "iohyve",
|
||||
"id" : "fooid",
|
||||
"args" : {
|
||||
"action" : "start",
|
||||
"name" : "bsdguest"
|
||||
},
|
||||
"namespace" : "sysadm"
|
||||
}
|
||||
|
||||
**Response**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"args": {
|
||||
"start": {
|
||||
"name": "bsdguest"
|
||||
}
|
||||
},
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
|
||||
.. index:: stop, iohyve
|
||||
|
||||
.. _Stop VM:
|
||||
|
||||
Stop VM
|
||||
=======
|
||||
|
||||
The "stop" action stops the specified VM.
|
||||
|
||||
**REST Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
PUT /sysadm/iohyve
|
||||
{
|
||||
"action" : "stop",
|
||||
"name" : "bsdguest"
|
||||
}
|
||||
|
||||
**WebSocket Request**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"id" : "fooid",
|
||||
"args" : {
|
||||
"action" : "stop",
|
||||
"name" : "bsdguest"
|
||||
},
|
||||
"name" : "iohyve",
|
||||
"namespace" : "sysadm"
|
||||
}
|
||||
|
||||
**Response**
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"args": {
|
||||
"stop": {
|
||||
"name": "bsdguest"
|
||||
}
|
||||
},
|
||||
"id": "fooid",
|
||||
"name": "response",
|
||||
"namespace": "sysadm"
|
||||
}
|
||||
@@ -68,6 +68,52 @@ bool AuthorizationManager::hasFullAccess(QString token){
|
||||
return ok;
|
||||
}
|
||||
|
||||
//SSL Certificate register/revoke/list
|
||||
bool AuthorizationManager::RegisterCertificate(QString token, QSslCertificate cert){
|
||||
if(!checkAuth(token)){ return false; }
|
||||
QString user = hashID(token).section("::::",2,2); //get the user name from the currently-valid token
|
||||
CONFIG->setValue("RegisteredCerts/"+user+"/"+QString(cert.publicKey().toPem()), cert.toText());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AuthorizationManager::RevokeCertificate(QString token, QString key, QString user){
|
||||
//user will be the current user if not empty - cannot touch other user's certs without full perms on current session
|
||||
QString cuser = hashID(token).section("::::",2,2);
|
||||
if(user.isEmpty()){ user = cuser; } //only probe current user
|
||||
if(user !=cuser){
|
||||
//Check permissions for this cross-user action
|
||||
if(!hasFullAccess(token)){ return false; }
|
||||
}
|
||||
//Check that the given cert exists first
|
||||
if( !CONFIG->contains("RegisteredCerts/"+user+"/"+key) ){ return false; }
|
||||
CONFIG->remove("RegisteredCerts/"+user+"/"+key);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AuthorizationManager::ListCertificates(QString token, QJsonObject *out){
|
||||
QStringList keys; //Format: "RegisteredCerts/<user>/<key>"
|
||||
if( hasFullAccess(token) ){
|
||||
//Read all user's certs
|
||||
keys = CONFIG->allKeys().filter("RegisteredCerts/");
|
||||
}else{
|
||||
//Only list certs for current user
|
||||
QString cuser = hashID(token).section("::::",2,2);
|
||||
keys = CONFIG->allKeys().filter("RegisteredCerts/"+cuser+"/");
|
||||
}
|
||||
keys.sort();
|
||||
//Now put the known keys into the output structure arranged by username/key
|
||||
QJsonObject user; QString username;
|
||||
for(int i=0; i<keys.length(); i++){
|
||||
if(username!=keys[i].section("/",1,1)){
|
||||
if(!user.isEmpty()){ out->insert(username, user); user = QJsonObject(); } //save the current info to the output
|
||||
username = keys[i].section("/",1,1); //save the new username for later
|
||||
}
|
||||
user.insert(keys[i].section("/",2,3000), CONFIG->value(keys[i]).toString() ); //just in case the key has additional "/" in it
|
||||
}
|
||||
if(!user.isEmpty() && !username.isEmpty()){ out->insert(username, user); }
|
||||
}
|
||||
|
||||
//Generic functions
|
||||
int AuthorizationManager::checkAuthTimeoutSecs(QString token){
|
||||
//Return the number of seconds that a token is valid for
|
||||
if(!HASH.contains(token)){ return 0; } //invalid token
|
||||
@@ -89,14 +135,14 @@ QString AuthorizationManager::LoginUP(QHostAddress host, QString user, QString p
|
||||
return ""; //user not allowed access if not in either of the wheel/operator groups
|
||||
}
|
||||
}else{ isOperator = true; }
|
||||
qDebug() << "Check username/password" << user << pass << localhost;
|
||||
//qDebug() << "Check username/password" << user << pass << localhost;
|
||||
//Need to run the full username/password through PAM
|
||||
if(!localhost || user=="root" || user=="toor"){
|
||||
ok = pam_checkPW(user,pass);
|
||||
}else{
|
||||
ok = true; //allow local access for users without password
|
||||
}
|
||||
|
||||
|
||||
qDebug() << "User Login Attempt:" << user << " Success:" << ok << " IP:" << host.toString();
|
||||
LogManager::log(LogManager::HOST, QString("User Login Attempt: ")+user+" Success: "+(ok?"true":"false")+" IP: "+host.toString() );
|
||||
if(!ok){
|
||||
@@ -108,12 +154,55 @@ QString AuthorizationManager::LoginUP(QHostAddress host, QString user, QString p
|
||||
}else{
|
||||
//valid login - generate a new token for it
|
||||
ClearHostFail(host.toString());
|
||||
return generateNewToken(isOperator);
|
||||
return generateNewToken(isOperator, user);
|
||||
}
|
||||
}
|
||||
|
||||
QString AuthorizationManager::LoginUC(QHostAddress host, QString user, QList<QSslCertificate> certs){
|
||||
//Login w/ username & SSL certificate
|
||||
bool localhost = ( (host== QHostAddress::LocalHost) || (host== QHostAddress::LocalHostIPv6) || (host.toString()=="::ffff:127.0.0.1") );
|
||||
bool ok = false;
|
||||
//First check that the user is valid on the system and part of the operator group
|
||||
bool isOperator = false;
|
||||
if(user!="root" && user!="toor"){
|
||||
QStringList groups = getUserGroups(user);
|
||||
if(groups.contains("wheel")){ isOperator = true; } //full-access user
|
||||
else if(!groups.contains("operator")){
|
||||
return ""; //user not allowed access if not in either of the wheel/operator groups
|
||||
}
|
||||
}else{ isOperator = true; }
|
||||
//qDebug() << "Check username/certificate combination" << user << localhost;
|
||||
|
||||
//Need to check the registered certificates for the designated user
|
||||
if(!localhost || user=="root" || user=="toor"){
|
||||
for(int i=0; i<certs.length() && !ok; i++){
|
||||
if(CONFIG->contains("RegisteredCerts/"+user+"/"+QString(certs[i].publicKey().toPem()) ) ){
|
||||
//Cert was registered - check expiration info
|
||||
// TO-DO
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
ok = true; //allow local access for users without password
|
||||
}
|
||||
|
||||
qDebug() << "User Login Attempt:" << user << " Success:" << ok << " IP:" << host.toString();
|
||||
LogManager::log(LogManager::HOST, QString("User Login Attempt: ")+user+" Success: "+(ok?"true":"false")+" IP: "+host.toString() );
|
||||
if(!ok){
|
||||
//invalid login
|
||||
//Bump the fail count for this host
|
||||
bool overlimit = BumpFailCount(host.toString());
|
||||
if(overlimit){ emit BlockHost(host); }
|
||||
return (overlimit ? "REFUSED" : "");
|
||||
}else{
|
||||
//valid login - generate a new token for it
|
||||
ClearHostFail(host.toString());
|
||||
return generateNewToken(isOperator, user);
|
||||
}
|
||||
}
|
||||
|
||||
QString AuthorizationManager::LoginService(QHostAddress host, QString service){
|
||||
bool localhost = ( (host== QHostAddress::LocalHost) || (host== QHostAddress::LocalHostIPv6) );
|
||||
bool localhost = ( (host== QHostAddress::LocalHost) || (host== QHostAddress::LocalHostIPv6) || (host.toString()=="::ffff:127.0.0.1") );
|
||||
|
||||
//Login a particular automated service
|
||||
qDebug() << "Service Login Attempt:" << service << " Success:" << localhost;
|
||||
@@ -136,13 +225,13 @@ QString AuthorizationManager::LoginService(QHostAddress host, QString service){
|
||||
}else{
|
||||
return "";
|
||||
}
|
||||
}else{ return generateNewToken(false); }//services are never given operator privileges
|
||||
}else{ return generateNewToken(false, service); }//services are never given operator privileges
|
||||
}
|
||||
|
||||
// =========================
|
||||
// PRIVATE
|
||||
// =========================
|
||||
QString AuthorizationManager::generateNewToken(bool isOp){
|
||||
QString AuthorizationManager::generateNewToken(bool isOp, QString user){
|
||||
QString tok;
|
||||
for(int i=0; i<TOKENLENGTH; i++){
|
||||
tok.append( AUTHCHARS.at( qrand() % AUTHCHARS.length() ) );
|
||||
@@ -150,10 +239,10 @@ QString AuthorizationManager::generateNewToken(bool isOp){
|
||||
|
||||
if( !hashID(tok).isEmpty() ){
|
||||
//Just in case the randomizer came up with something identical - re-run it
|
||||
tok = generateNewToken(isOp);
|
||||
tok = generateNewToken(isOp, user);
|
||||
}else{
|
||||
//unique token created - add it to the hash with the current time (+timeout)
|
||||
QString id = tok + "::::"+(isOp ? "operator" : "user"); //append operator status to auth key
|
||||
QString id = tok + "::::"+(isOp ? "operator" : "user")+"::::"+user; //append operator status to auth key
|
||||
HASH.insert(id, QDateTime::currentDateTime().addSecs(TIMEOUTSECS) );
|
||||
}
|
||||
return tok;
|
||||
|
||||
@@ -19,17 +19,23 @@ public:
|
||||
bool checkAuth(QString token); //see if the given token is valid
|
||||
bool hasFullAccess(QString token); //see if the token is associated with a full-access account
|
||||
|
||||
//SSL Certificate register/revoke/list (should only run if the current token is valid)
|
||||
bool RegisterCertificate(QString token, QSslCertificate cert); //if token is valid, register the given cert for future logins
|
||||
bool RevokeCertificate(QString token, QString key, QString user=""); //user will be the current user if not empty - cannot touch other user's certs without full perms on current session
|
||||
void ListCertificates(QString token, QJsonObject *out);
|
||||
|
||||
int checkAuthTimeoutSecs(QString token); //Return the number of seconds that a token is valid for
|
||||
|
||||
// == Token Generation functions
|
||||
QString LoginUP(QHostAddress host, QString user, QString pass); //Login w/ username & password
|
||||
QString LoginUC(QHostAddress host, QString user, QList<QSslCertificate> certs); //Login w/ username & SSL certificate
|
||||
QString LoginService(QHostAddress host, QString service); //Login a particular automated service
|
||||
|
||||
private:
|
||||
QHash<QString, QDateTime> HASH;
|
||||
QHash <QString, QDateTime> IPFAIL;
|
||||
|
||||
QString generateNewToken(bool isOperator);
|
||||
QString generateNewToken(bool isOperator, QString name);
|
||||
QStringList getUserGroups(QString user);
|
||||
|
||||
//Failure count management
|
||||
|
||||
@@ -25,7 +25,6 @@ EventWatcher::~EventWatcher(){
|
||||
}
|
||||
|
||||
void EventWatcher::start(){
|
||||
// - DISPATCH Events
|
||||
starting = true;
|
||||
// - Life Preserver Events
|
||||
WatcherUpdate(LPLOG); //load it initially (will also add it to the watcher);
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
protected:
|
||||
void incomingConnection(qintptr socketDescriptor){
|
||||
QSslSocket *serverSocket = new QSslSocket(this);
|
||||
qDebug() << "New Ssl Connection:";
|
||||
//qDebug() << "New Ssl Connection:";
|
||||
//setup any supported encruption types here
|
||||
serverSocket->setSslConfiguration(QSslConfiguration::defaultConfiguration());
|
||||
serverSocket->setProtocol(SSLVERSION);
|
||||
|
||||
@@ -31,6 +31,8 @@ RestOutputStruct::ExitCode WebSocket::AvailableSubsystems(bool allaccess, QJsonO
|
||||
<namespace2/name2> : <read/write/other>,
|
||||
}
|
||||
*/
|
||||
// - server settings (always available)
|
||||
out->insert("sysadm/settings","read/write");
|
||||
|
||||
// - syscache
|
||||
if(QFile::exists("/var/run/syscache.pipe")){
|
||||
@@ -41,7 +43,7 @@ RestOutputStruct::ExitCode WebSocket::AvailableSubsystems(bool allaccess, QJsonO
|
||||
if(QFile::exists("/usr/local/sbin/beadm")){
|
||||
out->insert("sysadm/beadm", "read/write");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// - dispatcher (Internal to server - always available)
|
||||
//"read" is the event notifications, "write" is the ability to queue up jobs
|
||||
@@ -95,7 +97,9 @@ RestOutputStruct::ExitCode WebSocket::EvaluateBackendRequest(const RestInputStru
|
||||
}
|
||||
|
||||
//Go through and forward this request to the appropriate sub-system
|
||||
if(namesp=="rpc" && name=="dispatcher"){
|
||||
if(namesp=="sysadm" && name=="settings"){
|
||||
return EvaluateSysadmSettingsRequest(IN.args, out);
|
||||
}else if(namesp=="rpc" && name=="dispatcher"){
|
||||
return EvaluateDispatcherRequest(IN.fullaccess, IN.args, out);
|
||||
}else if(namesp=="sysadm" && name=="beadm"){
|
||||
return EvaluateSysadmBEADMRequest(IN.args, out);
|
||||
@@ -119,6 +123,40 @@ RestOutputStruct::ExitCode WebSocket::EvaluateBackendRequest(const RestInputStru
|
||||
|
||||
}
|
||||
|
||||
// === SYSADM SETTINGS ===
|
||||
RestOutputStruct::ExitCode WebSocket::EvaluateSysadmSettingsRequest(const QJsonValue in_args, QJsonObject *out){
|
||||
if(!in_args.isObject()){ return RestOutputStruct::BADREQUEST; }
|
||||
QJsonObject argsO = in_args.toObject();
|
||||
QStringList keys = argsO.keys();
|
||||
if(!keys.contains("action")){ return RestOutputStruct::BADREQUEST; }
|
||||
QString act = argsO.value("action").toString();
|
||||
bool ok = false;
|
||||
if(act=="register_ssl_cert" && keys.contains("pub_key")){
|
||||
//Additional arguments: "pub_key" (String), and the cert with that key must already be loaded into the connection
|
||||
QString pub_key = argsO.value("pub_key").toString();\
|
||||
//Now find the currently-loaded certificate with the given public key
|
||||
QList<QSslCertificate> certs;
|
||||
if(SOCKET!=0){ certs = SOCKET->sslConfiguration().peerCertificateChain(); }
|
||||
else if(TSOCKET!=0){ certs = TSOCKET->peerCertificateChain(); }
|
||||
for(int i=0; i<certs.length() && !ok; i++){
|
||||
if(certs[i].publicKey().toPem()==pub_key){
|
||||
//Certificate found - register it
|
||||
ok = AUTHSYSTEM->RegisterCertificate(SockAuthToken, certs[i]);
|
||||
}
|
||||
}
|
||||
}else if(act=="list_ssl_certs"){
|
||||
AUTHSYSTEM->ListCertificates(SockAuthToken, out);
|
||||
ok = true; //always works for current user (even if nothing found)
|
||||
}else if(act=="revoke_ssl_cert" && keys.contains("pub_key") ){
|
||||
//Additional arguments: "user" (optional), "pub_key" (String)
|
||||
QString user; if(keys.contains("user")){ user = argsO.value("user").toString(); }
|
||||
ok = AUTHSYSTEM->RevokeCertificate(SockAuthToken,argsO.value("pub_key").toString(), user);
|
||||
}
|
||||
|
||||
if(ok){ return RestOutputStruct::OK; }
|
||||
else{ return RestOutputStruct::BADREQUEST; }
|
||||
}
|
||||
|
||||
//==== SYSCACHE ====
|
||||
RestOutputStruct::ExitCode WebSocket::EvaluateSyscacheRequest(const QJsonValue in_args, QJsonObject *out){
|
||||
//syscache only needs a list of sub-commands at the moment (might change later)
|
||||
@@ -436,6 +474,26 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmIocageRequest(const QJsonVal
|
||||
bool ok = false;
|
||||
if(keys.contains("action")){
|
||||
QString act = JsonValueToString(in_args.toObject().value("action"));
|
||||
if(act=="execjail"){
|
||||
ok = true;
|
||||
out->insert("execjail", sysadm::Iocage::execJail(in_args.toObject()));
|
||||
}
|
||||
if(act=="df"){
|
||||
ok = true;
|
||||
out->insert("df", sysadm::Iocage::df());
|
||||
}
|
||||
if(act=="destroyjail"){
|
||||
ok = true;
|
||||
out->insert("destroyjail", sysadm::Iocage::destroyJail(in_args.toObject()));
|
||||
}
|
||||
if(act=="createjail"){
|
||||
ok = true;
|
||||
out->insert("createjail", sysadm::Iocage::createJail(in_args.toObject()));
|
||||
}
|
||||
if(act=="clonejail"){
|
||||
ok = true;
|
||||
out->insert("clonejail", sysadm::Iocage::cloneJail(in_args.toObject()));
|
||||
}
|
||||
if(act=="cleanall"){
|
||||
ok = true;
|
||||
out->insert("cleanall", sysadm::Iocage::cleanAll());
|
||||
@@ -504,6 +562,10 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmIohyveRequest(const QJsonVal
|
||||
bool ok = false;
|
||||
if(keys.contains("action")){
|
||||
QString act = JsonValueToString(in_args.toObject().value("action"));
|
||||
if(act=="create"){
|
||||
ok = true;
|
||||
out->insert("create", sysadm::Iohyve::createGuest(in_args.toObject()));
|
||||
}
|
||||
if(act=="listvms"){
|
||||
ok = true;
|
||||
out->insert("listvms", sysadm::Iohyve::listVMs());
|
||||
@@ -512,6 +574,14 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmIohyveRequest(const QJsonVal
|
||||
ok = true;
|
||||
out->insert("fetchiso", sysadm::Iohyve::fetchISO(in_args.toObject()));
|
||||
}
|
||||
if(act=="install"){
|
||||
ok = true;
|
||||
out->insert("install", sysadm::Iohyve::installGuest(in_args.toObject()));
|
||||
}
|
||||
if(act=="issetup"){
|
||||
ok = true;
|
||||
out->insert("issetup", sysadm::Iohyve::isSetup());
|
||||
}
|
||||
if(act=="renameiso"){
|
||||
ok = true;
|
||||
out->insert("renameiso", sysadm::Iohyve::renameISO(in_args.toObject()));
|
||||
@@ -520,6 +590,18 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmIohyveRequest(const QJsonVal
|
||||
ok = true;
|
||||
out->insert("rmiso", sysadm::Iohyve::rmISO(in_args.toObject()));
|
||||
}
|
||||
if(act=="setup"){
|
||||
ok = true;
|
||||
out->insert("setup", sysadm::Iohyve::setupIohyve(in_args.toObject()));
|
||||
}
|
||||
if(act=="start"){
|
||||
ok = true;
|
||||
out->insert("start", sysadm::Iohyve::startGuest(in_args.toObject()));
|
||||
}
|
||||
if(act=="stop"){
|
||||
ok = true;
|
||||
out->insert("stop", sysadm::Iohyve::stopGuest(in_args.toObject()));
|
||||
}
|
||||
} //end of "action" key usage
|
||||
|
||||
//If nothing done - return the proper code
|
||||
|
||||
@@ -153,11 +153,20 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
|
||||
if(DEBUG){ qDebug() << "Authenticate Peer:" << SOCKET->peerAddress().toString(); }
|
||||
//Now do the auth
|
||||
if(out.in_struct.name=="auth" && out.in_struct.args.isObject() ){
|
||||
//username/password authentication
|
||||
//username/[password/cert] authentication
|
||||
QString user, pass;
|
||||
if(out.in_struct.args.toObject().contains("username")){ user = JsonValueToString(out.in_struct.args.toObject().value("username")); }
|
||||
if(out.in_struct.args.toObject().contains("password")){ pass = JsonValueToString(out.in_struct.args.toObject().value("password")); }
|
||||
SockAuthToken = AUTHSYSTEM->LoginUP(host, user, pass);
|
||||
if(!pass.isEmpty()){
|
||||
//Use the given password
|
||||
SockAuthToken = AUTHSYSTEM->LoginUP(host, user, pass);
|
||||
}else{
|
||||
//No password - use the current SSL certificates instead
|
||||
QList<QSslCertificate> certs;
|
||||
if(SOCKET!=0){ certs = SOCKET->sslConfiguration().peerCertificateChain(); }
|
||||
else if(TSOCKET!=0){ certs = TSOCKET->peerCertificateChain(); }
|
||||
SockAuthToken = AUTHSYSTEM->LoginUC(host, user, certs);
|
||||
}
|
||||
}else if(out.in_struct.name == "auth_token" && out.in_struct.args.isObject()){
|
||||
SockAuthToken = JsonValueToString(out.in_struct.args.toObject().value("token"));
|
||||
}else if(out.in_struct.name == "auth_clear"){
|
||||
|
||||
@@ -43,8 +43,14 @@ private:
|
||||
RestOutputStruct::ExitCode AvailableSubsystems(bool fullaccess, QJsonObject *out);
|
||||
// -- Main subsystem parser
|
||||
RestOutputStruct::ExitCode EvaluateBackendRequest(const RestInputStruct&, QJsonObject *out);
|
||||
|
||||
|
||||
// -- Individual subsystems
|
||||
// -- Server Settings Modification API
|
||||
RestOutputStruct::ExitCode EvaluateSysadmSettingsRequest(const QJsonValue in_args, QJsonObject *out);
|
||||
// -- rpc syscache API
|
||||
RestOutputStruct::ExitCode EvaluateSyscacheRequest(const QJsonValue in_args, QJsonObject *out);
|
||||
// -- rpc dispatcher API
|
||||
RestOutputStruct::ExitCode EvaluateDispatcherRequest(bool allaccess, const QJsonValue in_args, QJsonObject *out);
|
||||
// -- sysadm beadm API
|
||||
RestOutputStruct::ExitCode EvaluateSysadmBEADMRequest(const QJsonValue in_args, QJsonObject *out);
|
||||
|
||||
@@ -12,6 +12,207 @@ using namespace sysadm;
|
||||
|
||||
//PLEASE: Keep the functions in the same order as listed in pcbsd-general.h
|
||||
|
||||
// Execute a process in a jail on the box
|
||||
QJsonObject Iocage::execJail(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("jail")
|
||||
|| ! keys.contains("user")
|
||||
|| ! keys.contains("command") ) {
|
||||
retObject.insert("error", "Missing required keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the key values
|
||||
QString jail = jsin.value("jail").toString();
|
||||
QString user = jsin.value("user").toString();
|
||||
QString command = jsin.value("command").toString();
|
||||
|
||||
QStringList output;
|
||||
|
||||
output = General::RunCommand("iocage exec -U " + user + " " + jail + " " + command).split("\n");
|
||||
|
||||
QJsonObject vals;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).isEmpty() )
|
||||
break;
|
||||
|
||||
if ( output.at(i).indexOf("execvp:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
} else {
|
||||
QString key = output.at(i).simplified().section(":", 0, 0);
|
||||
QString value = output.at(i).simplified().section(":", 1, 1);
|
||||
|
||||
vals.insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
retObject.insert("success", vals);
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Show resource usage for jails on the box
|
||||
QJsonObject Iocage::df() {
|
||||
QJsonObject retObject;
|
||||
|
||||
// Get the key values
|
||||
QStringList output = General::RunCommand("iocage df").split("\n");
|
||||
QJsonObject vals;
|
||||
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
// Null output at first
|
||||
if ( output.at(i).isEmpty() )
|
||||
continue;
|
||||
|
||||
QJsonObject jail;
|
||||
QString line = output.at(i).simplified();
|
||||
QString uuid = line.section(" ", 0, 0);
|
||||
|
||||
// Otherwise we get a list of what we already know.
|
||||
if ( line.section(" ", 0, 0) == "UUID" )
|
||||
continue;
|
||||
|
||||
jail.insert("crt", line.section(" ", 1, 1));
|
||||
jail.insert("res", line.section(" ", 2, 2));
|
||||
jail.insert("qta", line.section(" ", 3, 3));
|
||||
jail.insert("use", line.section(" ", 4, 4));
|
||||
jail.insert("ava", line.section(" ", 5, 5));
|
||||
jail.insert("tag", line.section(" ", 6, 6));
|
||||
|
||||
retObject.insert(uuid, jail);
|
||||
}
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Destroy a jail on the box
|
||||
QJsonObject Iocage::destroyJail(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("jail") ) {
|
||||
retObject.insert("error", "Missing required keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the key values
|
||||
QString jail = jsin.value("jail").toString();
|
||||
QStringList output;
|
||||
|
||||
output = General::RunCommand("iocage destroy -f " + jail).split("\n");
|
||||
|
||||
QJsonObject vals;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).isEmpty() )
|
||||
break;
|
||||
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
} else {
|
||||
QString key = output.at(i).simplified().section(":", 0, 0);
|
||||
QString value = output.at(i).simplified().section(":", 1, 1);
|
||||
|
||||
vals.insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
retObject.insert("success", vals);
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Create a jail on the box
|
||||
QJsonObject Iocage::createJail(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
|
||||
// Get the key values
|
||||
QString switches = jsin.value("switches").toString();
|
||||
QString props = jsin.value("props").toString();
|
||||
QStringList output;
|
||||
|
||||
if ( keys.contains("switches" ) ) {
|
||||
output = General::RunCommand("iocage create " + switches + " " + props).split("\n");
|
||||
} else {
|
||||
output = General::RunCommand("iocage create " + props).split("\n");
|
||||
}
|
||||
|
||||
QJsonObject vals;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).isEmpty() )
|
||||
break;
|
||||
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
} else {
|
||||
QString key = output.at(i).simplified().section(":", 0, 0);
|
||||
QString value = output.at(i).simplified().section(":", 1, 1);
|
||||
|
||||
if ( keys.contains("switches" ) ) {
|
||||
vals.insert("uuid", key);
|
||||
} else {
|
||||
vals.insert(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retObject.insert("switches", switches);
|
||||
retObject.insert("props", props);
|
||||
retObject.insert("success", vals);
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Clone a jail on the box
|
||||
QJsonObject Iocage::cloneJail(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("jail") ) {
|
||||
retObject.insert("error", "Missing required keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the key values
|
||||
QString jail = jsin.value("jail").toString();
|
||||
QString props = jsin.value("props").toString();
|
||||
|
||||
QStringList output = General::RunCommand("iocage clone " + jail + " " + props).split("\n");
|
||||
|
||||
QJsonObject vals;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).isEmpty() )
|
||||
break;
|
||||
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
} else {
|
||||
QString key = output.at(i).simplified().section(":", 0, 0);
|
||||
QString value = output.at(i).simplified().section(":", 1, 1);
|
||||
|
||||
vals.insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
retObject.insert("jail", jail);
|
||||
retObject.insert("props", props);
|
||||
retObject.insert("success", vals);
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Clean everything iocage related on a box
|
||||
QJsonObject Iocage::cleanAll() {
|
||||
QJsonObject retObject;
|
||||
@@ -291,17 +492,33 @@ QJsonObject Iocage::getDefaultSettings() {
|
||||
// Return all of the jail settings
|
||||
QJsonObject Iocage::getJailSettings(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("jail") ) {
|
||||
retObject.insert("error", "Missing required keys");
|
||||
return retObject;
|
||||
}
|
||||
QStringList output;
|
||||
|
||||
// Get the key values
|
||||
QString jail = jsin.value("jail").toString();
|
||||
QString prop = jsin.value("prop").toString();
|
||||
|
||||
QStringList output = General::RunCommand("iocage get all " + jail).split("\n");
|
||||
QString switches = jsin.value("switches").toString();
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("jail")
|
||||
&& keys.contains("prop")
|
||||
&& keys.contains("switches") ) {
|
||||
output = General::RunCommand("iocage get " + switches + " " + prop).split("\n");
|
||||
} else if ( ! keys.contains("jail")
|
||||
&& ! keys.contains("prop")
|
||||
&& ! keys.contains("switches") ){
|
||||
retObject.insert("error", "Missing required keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
if ( ! keys.contains("prop")
|
||||
&& ! keys.contains("switches") ) {
|
||||
output = General::RunCommand("iocage get all " + jail).split("\n");
|
||||
} else if ( keys.contains("prop")
|
||||
&& ! keys.contains("switches") ) {
|
||||
output = General::RunCommand("iocage get " + prop + " " + jail).split("\n");
|
||||
}
|
||||
|
||||
QJsonObject vals;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
@@ -312,13 +529,42 @@ QJsonObject Iocage::getJailSettings(QJsonObject jsin) {
|
||||
if ( output.at(i).isEmpty() )
|
||||
break;
|
||||
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
} else {
|
||||
QString key = output.at(i).simplified().section(":", 0, 0);
|
||||
QString value = output.at(i).simplified().section(":", 1, 1);
|
||||
|
||||
if ( keys.contains("switches" ) ) {
|
||||
QString line = output.at(i).simplified();
|
||||
|
||||
// Otherwise we get a list of what we already know.
|
||||
if ( line.section(" ", 0, 0) == "UUID" )
|
||||
continue;
|
||||
|
||||
QJsonObject jail;
|
||||
QString uuid = line.section(" ", 0, 0);
|
||||
|
||||
jail.insert("TAG", line.section(" ", 1, 1));
|
||||
jail.insert(prop, line.section(" ", 2, 2));
|
||||
retObject.insert(uuid, jail);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( keys.contains("prop" )
|
||||
&& ! keys.contains("switches")
|
||||
&& prop != "all") {
|
||||
vals.insert(prop, key);
|
||||
retObject.insert(jail, vals);
|
||||
continue;
|
||||
}
|
||||
|
||||
vals.insert(key, value);
|
||||
retObject.insert(jail, vals);
|
||||
}
|
||||
}
|
||||
|
||||
retObject.insert(jail, vals);
|
||||
return retObject;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,11 @@ namespace sysadm{
|
||||
|
||||
class Iocage{
|
||||
public:
|
||||
static QJsonObject execJail(QJsonObject);
|
||||
static QJsonObject df();
|
||||
static QJsonObject destroyJail(QJsonObject);
|
||||
static QJsonObject createJail(QJsonObject);
|
||||
static QJsonObject cloneJail(QJsonObject);
|
||||
static QJsonObject cleanAll();
|
||||
static QJsonObject cleanTemplates();
|
||||
static QJsonObject cleanReleases();
|
||||
|
||||
@@ -13,6 +13,36 @@
|
||||
using namespace sysadm;
|
||||
|
||||
//PLEASE: Keep the functions in the same order as listed in pcbsd-general.h
|
||||
|
||||
// Create a new guest VM
|
||||
QJsonObject Iohyve::createGuest(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("name") || !keys.contains("size") ) {
|
||||
retObject.insert("error", "Missing required key(s) 'name/size'");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the key values
|
||||
QString name = jsin.value("name").toString();
|
||||
QString size = jsin.value("size").toString();
|
||||
|
||||
QStringList output = General::RunCommand("iohyve create " + name + " " + size).split("\n");
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("cannot create") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
// Return some details to user that the action was queued
|
||||
retObject.insert("name", name);
|
||||
retObject.insert("size", size);
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Queue the fetch of an ISO
|
||||
QJsonObject Iohyve::fetchISO(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
@@ -39,6 +69,49 @@ QJsonObject Iohyve::fetchISO(QJsonObject jsin) {
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Create a new guest VM
|
||||
QJsonObject Iohyve::installGuest(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("name") || !keys.contains("iso") ) {
|
||||
retObject.insert("error", "Missing required key(s) 'name/iso'");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the key values
|
||||
QString name = jsin.value("name").toString();
|
||||
QString iso = jsin.value("iso").toString();
|
||||
|
||||
QStringList output = General::RunCommand("iohyve install " + name + " " + iso).split("\n");
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("Could not open") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
// Return some details to user that the action was queued
|
||||
retObject.insert("name", name);
|
||||
retObject.insert("iso", iso);
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Return if iohyve is setup on the box
|
||||
QJsonObject Iohyve::isSetup() {
|
||||
QJsonObject retObject;
|
||||
|
||||
// Check if iohyve is setup on this box
|
||||
// We check the flags variable, enabling / disabling is done via service mgmt
|
||||
QString ioflags = General::getConfFileValue("/etc/rc.conf", "iohyve_flags=", 1);
|
||||
if ( ioflags.isEmpty() )
|
||||
retObject.insert("setup", "false");
|
||||
else
|
||||
retObject.insert("setup", "true");
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// List the VMs on the box
|
||||
QJsonObject Iohyve::listVMs() {
|
||||
@@ -156,3 +229,65 @@ QJsonObject Iohyve::setupIohyve(QJsonObject jsin) {
|
||||
retObject.insert("nic", nic);
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Start a guest
|
||||
QJsonObject Iohyve::startGuest(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("name") ) {
|
||||
retObject.insert("error", "Missing required key 'name'");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the key values
|
||||
QString name = jsin.value("name").toString();
|
||||
|
||||
// Do the setup right now
|
||||
QStringList output = General::RunCommand("iohyve start " + name).split("\n");
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("Not a valid") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
retObject.insert("name", name);
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Stop a guest
|
||||
QJsonObject Iohyve::stopGuest(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("name") ) {
|
||||
retObject.insert("error", "Missing required key 'name'");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the key values
|
||||
QString name = jsin.value("name").toString();
|
||||
|
||||
QString stoparg = "stop";
|
||||
if (! keys.contains("force") ) {
|
||||
if ( jsin.value("force").toString() == "true" ) {
|
||||
stoparg = "forcekill";
|
||||
}
|
||||
}
|
||||
|
||||
// Do the stop right now
|
||||
QStringList output = General::RunCommand("iohyve " + stoparg + " " + name).split("\n");
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
// This doesn't work, iohyve doesn't return error message right now
|
||||
if ( output.at(i).indexOf("No such guest") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
retObject.insert("name", name);
|
||||
return retObject;
|
||||
}
|
||||
|
||||
@@ -14,11 +14,16 @@ namespace sysadm{
|
||||
|
||||
class Iohyve{
|
||||
public:
|
||||
static QJsonObject createGuest(QJsonObject);
|
||||
static QJsonObject fetchISO(QJsonObject);
|
||||
static QJsonObject installGuest(QJsonObject);
|
||||
static QJsonObject isSetup();
|
||||
static QJsonObject listVMs();
|
||||
static QJsonObject renameISO(QJsonObject);
|
||||
static QJsonObject rmISO(QJsonObject);
|
||||
static QJsonObject setupIohyve(QJsonObject);
|
||||
static QJsonObject startGuest(QJsonObject);
|
||||
static QJsonObject stopGuest(QJsonObject);
|
||||
};
|
||||
|
||||
} //end of pcbsd namespace
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define DEBUG 0
|
||||
|
||||
//Create any global classes
|
||||
QSettings *CONFIG = new QSettings("PCBSD","sysadm");
|
||||
QSettings *CONFIG = new QSettings("/usr/local/etc/sysadm.conf", QSettings::IniFormat);
|
||||
EventWatcher *EVENTS = new EventWatcher();
|
||||
Dispatcher *DISPATCHER = new Dispatcher();
|
||||
bool WS_MODE = false;
|
||||
@@ -91,6 +91,7 @@ int main( int argc, char ** argv )
|
||||
//Start the daemon
|
||||
int ret = 1; //error return value
|
||||
if( w->startServer(port, websocket) ){
|
||||
qDebug() << " - Configuration File:" << CONFIG->fileName();
|
||||
QThread TBACK, TBACK2;
|
||||
EVENTS->moveToThread(&TBACK);
|
||||
DISPATCHER->moveToThread(&TBACK2);
|
||||
|
||||
Reference in New Issue
Block a user