diff --git a/.gitignore b/.gitignore index ce0fb10..a423326 100644 --- a/.gitignore +++ b/.gitignore @@ -1,43 +1,60 @@ -src/Makefile -src/binary/Makefile src/binary/main.o +src/binary/Makefile src/binary/sysadm -src/library/Makefile -src/library/NetDevice.o src/library/libsysadm.so src/library/libsysadm.so.1 src/library/libsysadm.so.1.0 src/library/libsysadm.so.1.0.0 +src/library/Makefile +src/library/NetDevice.o +src/library/sysadm-firewall.o src/library/sysadm-general.o src/library/sysadm-lifepreserver.o src/library/sysadm-network.o -src/library/sysadm-firewall.o src/library/sysadm-servicemanager.o src/library/sysadm-systeminfo.o src/library/sysadm-update.o src/library/sysadm-usermanager.o +src/Makefile src/server/AuthorizationManager.o -src/server/Makefile -src/server/WebBackend.o -src/server/WebServer.o -src/server/WebSocket.o src/server/dispatcher-client.o +src/server/Dispatcher.o +src/server/EventWatcher.o +src/server/LogManager.o src/server/main.o +src/server/Makefile src/server/moc_AuthorizationManager.cpp src/server/moc_AuthorizationManager.o -src/server/moc_WebServer.cpp -src/server/moc_WebServer.o -src/server/moc_WebSocket.cpp -src/server/moc_WebSocket.o src/server/moc_dispatcher-client.cpp src/server/moc_dispatcher-client.o -src/server/moc_syscache-client.cpp -src/server/moc_syscache-client.o -src/server/sysadm-server -src/server/syscache-client.o -src/server/EventWatcher.o +src/server/moc_Dispatcher.cpp +src/server/moc_Dispatcher.o src/server/moc_EventWatcher.cpp src/server/moc_EventWatcher.o src/server/moc_SslServer.cpp src/server/moc_SslServer.o - +src/server/moc_syscache-client.cpp +src/server/moc_syscache-client.o +src/server/moc_WebServer.cpp +src/server/moc_WebServer.o +src/server/moc_WebSocket.cpp +src/server/moc_WebSocket.o +src/server/NetDevice.o +src/server/sysadm-beadm.o +src/server/sysadm-firewall.o +src/server/sysadm-general.o +src/server/sysadm-iocage.o +src/server/sysadm-iohyve.o +src/server/sysadm-lifepreserver.o +src/server/sysadm-network.o +src/server/sysadm-server +src/server/sysadm-servicemanager.o +src/server/sysadm-systeminfo.o +src/server/sysadm-systemmanager.o +src/server/sysadm-update.o +src/server/sysadm-usermanager.o +src/server/syscache-client.o +src/server/WebBackend.o +src/server/WebServer.o +src/server/WebSocket.o +tests/node_modules/ diff --git a/README.md b/README.md index 9644995..7c8a802 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,88 @@ -# sysadm + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* -Official repo for PC-BSD's sysadm utility and websocket server +- [SysAdm](#sysadm) + - [Required Qt Modules](#required-qt-modules) + - [Building SysAdm](#building-sysadm) + - [Starting SysAdm](#starting-sysadm) + - [API Documentation](#api-documentation) + - [Contributing new API calls](#contributing-new-api-calls) + - [Adding new Classes for API calls](#adding-new-classes-for-api-calls) + - [Testing new API calls / classes](#testing-new-api-calls--classes) -### + -This repo contains all the Qt5 code necessary to build the following: +# SysAdm + +Official repo for PC-BSD's sysadm middleware WebSocket & REST server + +This middleware acts as the core for controlling a PC-BSD or FreeBSD
+system either locally or remotely via WebSockets or REST. + +### Required Qt Modules ``` - - sysadm-daemon - Backend daemon which handles all middleware / library - requests and functionality - - sysadm-ws - Websocket server, which handles incoming requests - for both remote and local wss:// connections - - sysadm - Command line interface to send/recv json requests +Qt5 Core (pkg install qt5-core) +Qt5 Concurrent (pkg install qt5-concurrent) +Qt5 Websockets (pkg install qt5-websockets) ``` + +### Building SysAdm + +``` +% git clone https://github.com/pcbsd/sysadm.git +% cd sysadm/src +% /usr/local/lib/qt5/bin/qmake -recursive +% make && sudo make install +``` + +### Starting SysAdm + +``` +(For WebSockets - Required for SysAdm Client) +% sudo sysrc -f /etc/rc.conf sysadm_websocket_enable="YES" +% sudo service sysadm-websocket start + +(Optional for REST) +% sudo sysrc -f /etc/rc.conf sysadm_restserver_enable="YES" +% sudo service sysadm-restserver start +``` + +### API Documentation + +https://api.pcbsd.org + +### Contributing new API calls + +Adding new API calls to the middleware is very straight-forward, simply
+add a new function which accepts JSON in, and returns JSON, then connect
+it to the backend. + +Example: +https://github.com/pcbsd/sysadm/commit/4d3b590f460d301b9376a063f9407dabfd7c9c66 + +### Adding new Classes for API calls + +Adding a new API class requires tweaking a few more files than a new API call only. + +Example: +https://github.com/pcbsd/sysadm/commit/1ba65b33880e2298ade3e5cc4f2718aa6112e44f + +### Testing new API calls / classes + +Before committing or sending a pull request, you'll need to run our
+"api-test.sh" script and confirm it works properly. To do so, first add
+your new call and restart the websocket server. Next do the following: + +``` +% cd sysadm/tests +% ./api-test.sh +``` + +The api-test script will prompt you to enter username, password, and some
+information about which class / API call to run. When that is done, and you
+have verified the functionality of your new call you should add the output
+of the test script (either from copy-n-paste, or from the file /tmp/api-response)
+to your commit. (This will allow us to document the new call / class) + diff --git a/api/classes/beadm.rst b/api/classes/beadm.rst new file mode 100644 index 0000000..b280685 --- /dev/null +++ b/api/classes/beadm.rst @@ -0,0 +1,140 @@ +.. _beadm: + +beadm +***** + +The beadm class is used to manage boot environments. + +Every beadm class request contains the following parameters: + ++---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Value** | **Description** | +| | | | ++=================================+===============+======================================================================================================================+ +| id | | any unique value for the request; examples include a hash, checksum, or uuid | +| | | | ++---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ +| name | beadm | | +| | | | ++---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ +| namespace | sysadm | | +| | | | ++---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ +| action | | supported actions include "listbes", "renamebe" | +| | | | ++---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ + +The rest of this section provides examples of the available *actions* for each type of request, along with their responses. + +.. index:: listbes, beadm + +.. _List Boot Environments: + +List Boot Environments +====================== + +The "listbes" action retrieves the list of boot environments. For each boot environment, the response includes its name, its flags (where "R" is active on reboot, "N" is active now and +"-" is inactive), the date it was created, its mount point, its nickname, and its size. + + +**REST Request** + +.. code-block:: json + + PUT /sysadm/beadm + { + "action" : "listbes" + } + +**WebSocket Request** + +.. code-block:: json + + { + "name" : "beadm", + "namespace" : "sysadm", + "id" : "fooid", + "args" : { + "action" : "listbes" + } + } + +**Response** + +.. code-block:: json + + { + "args": { + "listbes": { + "11.0-CURRENTJAN2016-up-20160128_150853": { + "active": "NR", + "date": "2016-01-28", + "mount": "/", + "nick": "14:57", + "space": "10.2G" + }, + "initial": { + "active": "-", + "date": "2016-01-28", + "mount": "-", + "nick": "07:00", + "space": "1.2G" + } + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: renamebe, beadm + +.. _Rename a Boot Environment: + +Rename a Boot Environment +========================= + +The "renamebe" action renames the specified boot environment. When using this action, specify the new name as the "source" and the boot environment as the "target". + + +**REST Request** + +.. code-block:: json + + PUT /sysadm/beadm + { + "source" : "newname", + "action" : "renamebe", + "target" : "bootthingy" + } + +**WebSocket Request** + +.. code-block:: json + + { + "namespace" : "sysadm", + "name" : "beadm", + "id" : "fooid", + "args" : { + "source" : "newname", + "target" : "bootthingy", + "action" : "renamebe" + } + } + +**Response** + +.. code-block:: json + + { + "args": { + "renamebe": { + "source": "newname", + "target": "bootthingy" + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } \ No newline at end of file diff --git a/api/classes/bootenvironments.rst b/api/classes/bootenvironments.rst deleted file mode 100644 index 6d220d0..0000000 --- a/api/classes/bootenvironments.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _bootenvironments: - -bootenvironments -================ - -Some intro text here... - diff --git a/api/classes/iocage.rst b/api/classes/iocage.rst index dea8b7a..4708288 100644 --- a/api/classes/iocage.rst +++ b/api/classes/iocage.rst @@ -20,7 +20,8 @@ Every iocage class request contains the following parameters: | namespace | sysadm | | | | | | +---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ -| action | | supported actions include "getdefaultsettings", "listjails", "getjailsettings" | +| action | | supported actions include "getdefaultsettings", "listjails", "getjailsettings", "startjail", "stopjail", | +| | | "capjail", "cleanjails", "cleanreleases", "cleantemplates", "cleanall", "activatepool", and "deactivatepool" | | | | | +---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ @@ -332,6 +333,7 @@ system boot, the jail ID (only applies to running jails), whether or not the jai "listjails": { "611c89ae-c43c-11e5-9602-54ee75595566": { "boot": "off", + "ip4": "-", "jid": "-", "state": "down", "tag": "testjail", @@ -363,6 +365,7 @@ system boot, the jail ID (only applies to running jails), whether or not the jai "listjails": { "611c89ae-c43c-11e5-9602-54ee75595566": { "boot": "off", + "ip4": "-", "jid": "-", "state": "down", "tag": "testjail", @@ -648,4 +651,557 @@ The "getjailsettings" action lists all of the settings that apply to the specifi "name": "response", "namespace": "sysadm" } - \ No newline at end of file + +.. index:: startjail, iocage + +.. _Start a Jail: + +Start a Jail +============ + +The "startjail" action starts the specified jail. + +.. note:: since a jail can only be started once, you will receive an error if the jail is already running. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iocage + { + "action" : "startjail", + "jail" : "test" + } + +**REST Response** + +.. code-block:: json + + { + "args": { + "startjail": { + "test": { + "* Starting 0bf985de-ca0f-11e5-8d45-d05099728dbf (test)": "", + "+ Started (shared IP mode) OK": "", + "+ Starting services OK": "" + } + } + } + } + +**WebSocket Request** + +.. code-block:: json + + { + "namespace" : "sysadm", + "id" : "fooid", + "args" : { + "action" : "startjail", + "jail" : "test" + }, + "name" : "iocage" + } + +**WebSocket Response** + +.. code-block:: json + + { + "args": { + "startjail": { + "test": { + "INFO": " 0bf985de-ca0f-11e5-8d45-d05099728dbf (test) is already up" + } + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: stopjail, iocage + +.. _Stop a Jail: + +Stop a Jail +=========== + +The "stopjail" action stops the specified jail. + +.. note:: since a jail can only be stopped once, you will receive an error if the jail is not running. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iocage + { + "action" : "stopjail", + "jail" : "test" + } + +**REST Response** + +.. code-block:: json + + { + "args": { + "stopjail": { + "test": { + "* Stopping 0bf985de-ca0f-11e5-8d45-d05099728dbf (test)": "", + "+ Removing jail process OK": "", + "+ Running post-stop OK": "", + "+ Running pre-stop OK": "", + "+ Stopping services OK": "" + } + } + } + } + +**WebSocket Request** + +.. code-block:: json + + { + "args" : { + "jail" : "test", + "action" : "stopjail" + }, + "namespace" : "sysadm", + "id" : "fooid", + "name" : "iocage" + } + +**WebSocket Response** + +.. code-block:: json + + { + "args": { + "stopjail": { + "test": { + "INFO": " 0bf985de-ca0f-11e5-8d45-d05099728dbf (test) is already down" + } + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: capjail, iocage + +.. _Cap a Jail: + +Cap a Jail +=========== + +The "capjail" action re-applies resource limits to a running jail. Use this action when you make a change to the specified jail's resources and want to apply the changes without restarting +the jail. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iocage + { + "jail" : "test", + "action" : "capjail" + } + +**WebSocket Request** + +.. code-block:: json + + { + "args" : { + "jail" : "test", + "action" : "capjail" + }, + "namespace" : "sysadm", + "name" : "iocage", + "id" : "fooid" + } + +**Response** + +.. code-block:: json + + { + "args": { + "capjail": { + "success": "jail test capped." + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: cleanjails, iocage + +.. _Clean Jails: + +Clean Jails +=========== + +The "cleanjails" action destroys all existing jail datasets, including all data stored in the jails. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iocage + { + "action" : "cleanjails" + } + +**WebSocket Request** + +.. code-block:: json + + { + "namespace" : "sysadm", + "args" : { + "action" : "cleanjails" + }, + "id" : "fooid", + "name" : "iocage" + } + +**Response** + +.. code-block:: json + + { + "args": { + "cleanjails": { + "success": "All jails have been cleaned." + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: cleanreleases, iocage + +.. _Clean Releases: + +Clean Releases +============== + +The "cleanreleases" action deletes all releases that have been fetched. Since basejails rely on releases, do not run this action if any basejails still exist. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iocage + { + "action" : "cleanreleases" + } + +**WebSocket Request** + +**REST Request** + +.. code-block:: json + + { + "id" : "fooid", + "namespace" : "sysadm", + "args" : { + "action" : "cleanreleases" + }, + "name" : "iocage" + } + +**Response** + +**REST Request** + +.. code-block:: json + + { + "args": { + "cleanreleases": { + "success": "All RELEASEs have been cleaned." + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: cleantemplates, iocage + +.. _Clean Templates: + +Clean Templates +=============== + +The "cleantemplates" action destroys all existing jail templates. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iocage + { + "action" : "cleantemplates" + } + +**WebSocket Request** + +.. code-block:: json + + { + "args" : { + "action" : "cleantemplates" + }, + "name" : "iocage", + "id" : "fooid", + "namespace" : "sysadm" + } + +**Response** + +.. code-block:: json + + { + "args": { + "cleantemplates": { + "success": "All templates have been cleaned." + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + + .. index:: cleanall, iocage + +.. _Clean All: + +Clean All +=========== + +The "cleanall" action destroys everything associated with iocage. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iocage + { + "action" : "cleanall" + } + +**WebSocket Request** + +.. code-block:: json + + { + "namespace" : "sysadm", + "args" : { + "action" : "cleanall" + }, + "id" : "fooid", + "name" : "iocage" + } + +**Response** + +.. code-block:: json + + { + "args": { + "cleanall": { + "success": "All iocage datasets have been cleaned." + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: activatepool, iocage + +.. _Activate a Pool: + +Activate a Pool +=============== + +The "activatepool" action can be used to specify which ZFS pool is used to store jails. If you do not specify the pool, the response will indicate the current setting. + +These examples specify the pool to use: + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iocage + { + "action" : "activatepool", + "pool" : "tank" + } + +**REST Response** + +.. code-block:: json + + { + "args": { + "activatepool": { + "success": "pool tank activated." + } + } + } + +**WebSocket Request** + +.. code-block:: json + + { + "args" : { + "action" : "activatepool", + "pool" : "tank" + }, + "name" : "iocage", + "id" : "fooid", + "namespace" : "sysadm" + } + +**WebSocket Response** + +.. code-block:: json + + { + "args": { + "activatepool": { + "success": "pool tank activated." + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +These examples show responses when the pool is not specified: + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iocage + { + "action" : "activatepool" + } + +**REST Response** + +.. code-block:: json + + { + "args": { + "activatepool": { + "currently active": { + "pool": " tank" + } + } + } + } + +**WebSocket Request** + +.. code-block:: json + + { + "args" : { + "action" : "activatepool" + }, + "namespace" : "sysadm", + "name" : "iocage", + "id" : "fooid" + } + +**WebSocket Response** + +.. code-block:: json + + { + "args": { + "activatepool": { + "currently active": { + "pool": " tank" + } + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + + .. index:: deactivatepool, iocage + +.. _Deactivate a Pool: + +Deactivate a Pool +================= + +Since only one pool can be active, the "deactivatepool" action can be used to deactivate a currently active pool. This should be done before using the +"activatepool" action to activate a different pool. When a pool is deactivated, no data is removed. However, you won't have access to its jails unless you move those datasets to the newly +activated pool or activate the old pool again. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iocage + { + "action" : "deactivatepool", + "pool" : "tank" + } + +**REST Response** + +.. code-block:: json + + { + "args": { + "deactivatepool": { + "success": "pool tank deactivated." + } + } + } + +**WebSocket Request** + +.. code-block:: json + + { + "id" : "fooid", + "name" : "iocage", + "args" : { + "pool" : "tank", + "action" : "deactivatepool" + }, + "namespace" : "sysadm" + } + +**WebSocket Response** + +.. code-block:: json + + { + "args": { + "deactivatepool": { + "success": "pool tank deactivated." + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } diff --git a/api/classes/iohyve.rst b/api/classes/iohyve.rst new file mode 100644 index 0000000..a944590 --- /dev/null +++ b/api/classes/iohyve.rst @@ -0,0 +1,247 @@ +.. _iohyve: + +iohyve +****** + +The iohyve class is used to manage virtual machines (VMs) running in the bhyve type 2 hypervisor. + +Every iohyve class request contains the following parameters: + ++---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ +| **Parameter** | **Value** | **Description** | +| | | | ++=================================+===============+======================================================================================================================+ +| id | | any unique value for the request; examples include a hash, checksum, or uuid | +| | | | ++---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ +| name | iohyve | | +| | | | ++---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ +| namespace | sysadm | | +| | | | ++---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ +| action | | supported actions include "listvms", "fetchiso", "renameiso", "rmiso" | +| | | | ++---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ + +The rest of this section provides examples of the available *actions* for each type of request, along with their responses. + +.. index:: listvms, iohyve + +.. _List VMs: + +List VMs +======== + +The "listvms" action lists information about currently installed VMs. For each VM, the response includes the VM's name, description, whether or not it is scheduled to start when the host +system boots, whether or not it is currently running, and whether or not the VM is currently loaded into memory. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iohyve + { + "action" : "listvms" + } + +**REST Response** + +.. code-block:: json + + { + "args": { + "listvms": { + "testguest": { + "description": "February 1, 2016 at 03:11:57 PM EST", + "rcboot": "NO", + "running": "NO", + "vmm": "YES" + } + } + } + } + +**WebSocket Request** + +.. code-block:: json + + { + "namespace" : "sysadm", + "args" : { + "action" : "listvms" + }, + "name" : "iohyve", + "id" : "fooid" + } + +**WebSocket Response** + +.. code-block:: json + + { + "args": { + "listvms": { + "testguest": { + "description": "February 1, 2016 at 03:11:57 PM EST", + "rcboot": "NO", + "running": "NO", + "vmm": "YES" + } + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: fetchiso, iohyve + +.. _Fetch ISO: + +Fetch ISO +========= + +The "fetchiso" action is used to retrieve the installation ISO. It is used with the "url" argument which contains the ISO address beginning with *http://*, +*ftp://*, or +*file://*. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iohyve + { + "url" : "ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/ISO-IMAGES/10.1/FreeBSD-10.1-RELEASE-amd64-disc1.iso", + "action" : "fetchiso" + } + +**WebSocket Request** + +.. code-block:: json + + { + "namespace" : "sysadm", + "name" : "iohyve", + "args" : { + "url" : "ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/ISO-IMAGES/10.1/FreeBSD-10.1-RELEASE-amd64-disc1.iso", + "action" : "fetchiso" + }, + "id" : "fooid" + } + +**Response** + +.. code-block:: json + + { + "args": { + "fetchiso": { + "command": "iohyve fetch ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/ISO-IMAGES/10.1/FreeBSD-10.1-RELEASE-amd64-disc1.iso", + "comment": "Task Queued", + "queueid": "{b3a8b980-a564-4ff8-86a2-1971bd4f58d1}" + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: renameiso, iohyve + +.. _Rename ISO: + +Rename ISO +========== + +The "renameiso" action is used to to rename an existing ISO file on disk. Specify the existing name with "source" and the new name with "target". + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iohyve + { + "source" : "test.iso", + "target" : "102.iso", + "action" : "renameiso" + } + +**WebSocket Request** + +.. code-block:: json + + { + "args" : { + "target" : "102.iso", + "source" : "test.iso", + "action" : "renameiso" + }, + "id" : "fooid", + "name" : "iohyve", + "namespace" : "sysadm" + } + +**Response** + +.. code-block:: json + + { + "args": { + "renameiso": { + "source": "test.iso", + "target": "102.iso" + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: rmiso, iohyve + +.. _Remove ISO: + +Remove ISO +========== + +The "rmiso" action is used to to remove an existing ISO file from disk. Specify the ISO's name as the "target". + +**REST Request** + +.. code-block:: json + + PUT /sysadm/iohyve + { + "action" : "rmiso", + "target" : "FreeBSD-10.2-RELEASE-amd64-bootonly.iso" + } + +**WebSocket Request** + +.. code-block:: json + + { + "id" : "fooid", + "name" : "iohyve", + "args" : { + "target" : "FreeBSD-10.2-RELEASE-amd64-bootonly.iso", + "action" : "rmiso" + }, + "namespace" : "sysadm" + } + +**Response** + +.. code-block:: json + + { + "args": { + "rmiso": { + "target": "FreeBSD-10.2-RELEASE-amd64-bootonly.iso" + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } \ No newline at end of file diff --git a/api/classes/systemmanager.rst b/api/classes/systemmanager.rst index e3ed573..bd48b09 100644 --- a/api/classes/systemmanager.rst +++ b/api/classes/systemmanager.rst @@ -1,9 +1,9 @@ .. _systemmanager: systemmanager -********** +************* -The systemmanager class is used to manage various aspects of the FreeBSD system. Every systemmanager class request contains the following parameters: +The systemmanager class is used to retrieve information about the system. Every systemmanager class request contains the following parameters: +---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ | **Parameter** | **Value** | **Description** | @@ -18,7 +18,8 @@ The systemmanager class is used to manage various aspects of the FreeBSD system. | namespace | sysadm | | | | | | +---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ -| action | | supported actions include "memorystats", "cpupercentage", "cputemps", "batteryinfo", "externalmounts", "systemmanager" | +| action | | supported actions include "memorystats", "cpupercentage", "cputemps", "procinfo", "killproc", "batteryinfo", | +| | | "externalmounts", "systemmanager", "sysctllist", and "setsysctl" | | | | | +---------------------------------+---------------+----------------------------------------------------------------------------------------------------------------------+ @@ -236,6 +237,154 @@ The "cputemps" action returns the temperature of each CPU. "namespace": "sysadm" } +.. index:: procinfo, systemmanager + +.. _Process Information: + +Process Information +=================== + +The "procinfo" action lists information about each running process. Since a system will have many running processes, the responses in this section only show one process as an example +of the type of information listed by this action. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/systemmanager + { + "action" : "procinfo" + } + +**REST Response** + +.. code-block:: json + + { + "args": { + "procinfo": { + "228": { + "command": "adjkerntz", + "cpu": "3", + "nice": "0", + "pri": "52", + "res": "1968K", + "size": "8276K", + "state": "pause", + "thr": "1", + "time": "0:00", + "username": "root", + "wcpu": "0.00%" + } + } + } + } + +**WebSocket Request** + +.. code-block:: json + + { + "id" : "fooid", + "namespace" : "sysadm", + "name" : "systemmanager", + "args" : { + "action" : "procinfo" + } + } + +**WebSocket Response** + +.. code-block:: json + + { + "args": { + "procinfo": { + "228": { + "command": "adjkerntz", + "cpu": "3", + "nice": "0", + "pri": "52", + "res": "1968K", + "size": "8276K", + "state": "pause", + "thr": "1", + "time": "0:00", + "username": "root", + "wcpu": "0.00%" + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: killproc, systemmanager + +.. _Kill a Process: + +Kill a Process +============== + +The "killproc" action can be used to send the specified signal to the specified Process ID (PID). The following signals are supported: INT, QUIT, ABRT, KILL, ALRM, or TERM. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/systemmanager + { + "signal" : "KILL", + "pid" : "13939", + "action" : "killproc" + } + +**REST Response** + +.. code-block:: json + + { + "args": { + "killproc": { + "action": "killproc", + "pid": "13939", + "signal": "KILL" + } + } + } + +**WebSocket Request** + +.. code-block:: json + + { + "namespace" : "sysadm", + "args" : { + "pid" : "13939", + "action" : "killproc", + "signal" : "KILL" + }, + "id" : "fooid", + "name" : "systemmanager" + } + +**WebSocket Response** + +.. code-block:: json + + { + "args": { + "killproc": { + "action": "killproc", + "pid": "13939", + "signal": "KILL" + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + .. index:: batteryinfo, systemmanager .. _Battery Information: @@ -436,3 +585,143 @@ of RAM, and the system's uptime. "name": "response", "namespace": "sysadm" } + +.. index:: sysctllist, systemmanager + +.. _List Sysctls: + +List Sysctls +============ + +The "sysctllist" action lists returns the list of all setable sysctl values. Since there are many, the example responses in this section have been truncated to just show a few. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/systemmanager + { + "action" : "sysctllist" + } + +**REST Response** + +.. code-block:: json + + { + "args": { + "sysctllist": { + "compat.ia32.maxdsiz": "536870912", + "compat.ia32.maxssiz": "67108864", + "compat.ia32.maxvmem": "0", + "compat.linux.osname": "Linux", + "compat.linux.osrelease": "2.6.18", + "compat.linux.oss_version": "198144", + "compat.linux32.maxdsiz": "536870912", + "compat.linux32.maxssiz": "67108864", + "compat.linux32.maxvmem": "0", + } + } + } + +**WebSocket Request** + +.. code-block:: json + + { + "name" : "systemmanager", + "namespace" : "sysadm", + "id" : "fooid", + "args" : { + "action" : "sysctllist" + } + } + +**WebSocket Response** + +.. code-block:: json + + { + "args": { + "sysctllist": { + "compat.ia32.maxdsiz": "536870912", + "compat.ia32.maxssiz": "67108864", + "compat.ia32.maxvmem": "0", + "compat.linux.osname": "Linux", + "compat.linux.osrelease": "2.6.18", + "compat.linux.oss_version": "198144", + "compat.linux32.maxdsiz": "536870912", + "compat.linux32.maxssiz": "67108864", + "compat.linux32.maxvmem": "0", + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } + +.. index:: setsysctl, systemmanager + +.. _Set a Sysctl: + +Set a Sysctl +============ + +The "setsysctl" action sets the specified setable sysctl to the specified value. The response indicates that the old value was changed to the new value. + +**REST Request** + +.. code-block:: json + + PUT /sysadm/systemmanager + { + "value" : "0", + "sysctl" : "security.jail.mount_devfs_allowed", + "action" : "setsysctl" + } + +**REST Response** + +.. code-block:: json + + { + "args": { + "setsysctl": { + "response": "security.jail.mount_devfs_allowed: 1 -> 0", + "sysctl": "security.jail.mount_devfs_allowed", + "value": "0" + } + } + } + +**WebSocket Request** + +.. code-block:: json + + { + "args" : { + "value" : "0", + "action" : "setsysctl", + "sysctl" : "security.jail.mount_devfs_allowed" + }, + "name" : "systemmanager", + "namespace" : "sysadm", + "id" : "fooid" + } + +**WebSocket Response** + +.. code-block:: json + + { + "args": { + "setsysctl": { + "response": "security.jail.mount_devfs_allowed: 1 -> 0", + "sysctl": "security.jail.mount_devfs_allowed", + "value": "0" + } + }, + "id": "fooid", + "name": "response", + "namespace": "sysadm" + } \ No newline at end of file diff --git a/api/classes/updates.rst b/api/classes/updates.rst index 85cae88..89f01be 100644 --- a/api/classes/updates.rst +++ b/api/classes/updates.rst @@ -162,7 +162,7 @@ The "startupdate" action starts the specified update. You must specify a "target * **fbsdupdatepkgs:** update installed software and apply FreeBSD system updates. -* **standalone:** only update package specified as a "tag" (e.g. pkgng-1.6.9). +* **standalone:** only apply the update specified as a "tag". Use the "checkupdates" action to determine the name (tag) of the update to specify. **REST Request** diff --git a/src/server/WebBackend.cpp b/src/server/WebBackend.cpp index bdcf431..689cf5c 100644 --- a/src/server/WebBackend.cpp +++ b/src/server/WebBackend.cpp @@ -1,4 +1,4 @@ -// =============================== +// =============================== // PC-BSD REST API Server // Available under the 3-clause BSD License // Written by: Ken Moore DEC 2015 @@ -9,6 +9,7 @@ #include //sysadm library interface classes +#include "library/sysadm-beadm.h" #include "library/sysadm-general.h" #include "library/sysadm-iocage.h" #include "library/sysadm-iohyve.h" @@ -36,6 +37,12 @@ RestOutputStruct::ExitCode WebSocket::AvailableSubsystems(bool allaccess, QJsonO out->insert("rpc/syscache","read"); //no write to syscache - only reads } + // - beadm + 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 out->insert("rpc/dispatcher", allaccess ? "read/write" : "read"); @@ -90,6 +97,8 @@ RestOutputStruct::ExitCode WebSocket::EvaluateBackendRequest(const RestInputStru //Go through and forward this request to the appropriate sub-system if(namesp=="rpc" && name=="dispatcher"){ return EvaluateDispatcherRequest(IN.fullaccess, IN.args, out); + }else if(namesp=="sysadm" && name=="beadm"){ + return EvaluateSysadmBEADMRequest(IN.args, out); }else if(namesp=="sysadm" && name=="iocage"){ return EvaluateSysadmIocageRequest(IN.args, out); }else if(namesp=="sysadm" && name=="iohyve"){ @@ -182,6 +191,33 @@ RestOutputStruct::ExitCode WebSocket::EvaluateDispatcherRequest(bool allaccess, return RestOutputStruct::OK; } +//==== SYSADM -- BEADM ==== +RestOutputStruct::ExitCode WebSocket::EvaluateSysadmBEADMRequest(const QJsonValue in_args, QJsonObject *out){ + if(in_args.isObject()){ + QStringList keys = in_args.toObject().keys(); + bool ok = false; + if(keys.contains("action")){ + QString act = JsonValueToString(in_args.toObject().value("action")); + if(act=="listbes"){ + ok = true; + out->insert("listbes", sysadm::BEADM::listBEs()); + } + if(act=="renamebe"){ + ok = true; + out->insert("renamebe", sysadm::BEADM::renameBE(in_args.toObject())); + } + } //end of "action" key usage + + //If nothing done - return the proper code + if(!ok){ + return RestOutputStruct::BADREQUEST; + } + }else{ // if(in_args.isArray()){ + return RestOutputStruct::BADREQUEST; + } + return RestOutputStruct::OK; +} + //==== SYSADM -- Network ==== RestOutputStruct::ExitCode WebSocket::EvaluateSysadmNetworkRequest(const QJsonValue in_args, QJsonObject *out){ if(in_args.isObject()){ @@ -389,6 +425,26 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmIocageRequest(const QJsonVal bool ok = false; if(keys.contains("action")){ QString act = JsonValueToString(in_args.toObject().value("action")); + if(act=="cleanall"){ + ok = true; + out->insert("cleanall", sysadm::Iocage::cleanAll()); + } + if(act=="cleantemplates"){ + ok = true; + out->insert("cleantemplates", sysadm::Iocage::cleanTemplates()); + } + if(act=="cleanreleases"){ + ok = true; + out->insert("cleanreleases", sysadm::Iocage::cleanReleases()); + } + if(act=="cleanjails"){ + ok = true; + out->insert("cleanjails", sysadm::Iocage::cleanJails()); + } + if(act=="capjail"){ + ok = true; + out->insert("capjail", sysadm::Iocage::capJail(in_args.toObject())); + } if(act=="deactivatepool"){ ok = true; out->insert("deactivatepool", sysadm::Iocage::deactivatePool(in_args.toObject())); @@ -441,7 +497,18 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmIohyveRequest(const QJsonVal ok = true; out->insert("listvms", sysadm::Iohyve::listVMs()); } - + if(act=="fetchiso"){ + ok = true; + out->insert("fetchiso", sysadm::Iohyve::fetchISO(in_args.toObject())); + } + if(act=="renameiso"){ + ok = true; + out->insert("renameiso", sysadm::Iohyve::renameISO(in_args.toObject())); + } + if(act=="rmiso"){ + ok = true; + out->insert("rmiso", sysadm::Iohyve::rmISO(in_args.toObject())); + } } //end of "action" key usage //If nothing done - return the proper code diff --git a/src/server/WebSocket.h b/src/server/WebSocket.h index 8981b14..4547a69 100644 --- a/src/server/WebSocket.h +++ b/src/server/WebSocket.h @@ -46,6 +46,8 @@ private: // -- Individual subsystems RestOutputStruct::ExitCode EvaluateSyscacheRequest(const QJsonValue in_args, QJsonObject *out); RestOutputStruct::ExitCode EvaluateDispatcherRequest(bool allaccess, const QJsonValue in_args, QJsonObject *out); + // -- sysadm beadm API + RestOutputStruct::ExitCode EvaluateSysadmBEADMRequest(const QJsonValue in_args, QJsonObject *out); // -- sysadm iocage API RestOutputStruct::ExitCode EvaluateSysadmIocageRequest(const QJsonValue in_args, QJsonObject *out); // -- sysadm iohyve API diff --git a/src/server/library/library.pri b/src/server/library/library.pri index dfc9b8d..53cb45e 100644 --- a/src/server/library/library.pri +++ b/src/server/library/library.pri @@ -3,6 +3,7 @@ CONFIG += c++11 HEADERS += $${PWD}/sysadm-global.h \ $${PWD}/sysadm-general.h \ + $${PWD}/sysadm-beadm.h \ $${PWD}/sysadm-iocage.h \ $${PWD}/sysadm-iohyve.h \ $${PWD}/sysadm-lifepreserver.h \ @@ -15,6 +16,7 @@ HEADERS += $${PWD}/sysadm-global.h \ SOURCES += $${PWD}/NetDevice.cpp \ $${PWD}/sysadm-general.cpp \ + $${PWD}/sysadm-beadm.cpp \ $${PWD}/sysadm-iocage.cpp \ $${PWD}/sysadm-iohyve.cpp \ $${PWD}/sysadm-lifepreserver.cpp \ diff --git a/src/server/library/sysadm-beadm.cpp b/src/server/library/sysadm-beadm.cpp new file mode 100644 index 0000000..56316aa --- /dev/null +++ b/src/server/library/sysadm-beadm.cpp @@ -0,0 +1,77 @@ +//=========================================== +// PC-BSD source code +// Copyright (c) 2015, PC-BSD Software/iXsystems +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include +#include "sysadm-general.h" +#include "sysadm-beadm.h" +#include "sysadm-global.h" +#include "globals.h" + +using namespace sysadm; + +//PLEASE: Keep the functions in the same order as listed in pcbsd-general.h + +// List all the available BEs +QJsonObject BEADM::listBEs() { + QJsonObject retObject; + + QStringList output = General::RunCommand("beadm list -H").split("\n"); + + for ( int i = 0; i < output.size(); i++) + { + + if ( output.at(i).isEmpty() ) + break; + + QString line = output.at(i).simplified(); + + QString beName = line.section(" ", 0, 0); + QString beActive = line.section(" ", 1, 1); + QString beMount = line.section(" ", 2, 2); + QString beSpace = line.section(" ", 3, 3); + QString beDate = line.section(" ", 4, 4); + QString beNick = line.section(" ", 5, 5); + + QJsonObject vals; + vals.insert("active", beActive); + vals.insert("mount", beMount); + vals.insert("space", beSpace); + vals.insert("date", beDate); + vals.insert("nick", beNick); + + retObject.insert(beName, vals); + } + + return retObject; +} + +QJsonObject BEADM::renameBE(QJsonObject jsin) { + QJsonObject retObject; + + QStringList keys = jsin.keys(); + if (! keys.contains("source") || ! keys.contains("target") ) { + retObject.insert("error", "Missing required key(s) 'source / target'"); + return retObject; + } + + // Get the key values + QString source = jsin.value("source").toString(); + QString target = jsin.value("target").toString(); + + + QStringList output = General::RunCommand("beadm rename " + source + " " + target).split("\n"); + for ( int i = 0; i < output.size(); i++) + { + if ( output.at(i).indexOf("ERROR") != -1 ) { + retObject.insert("error", output.at(i)); + return retObject; + } + } + + retObject.insert("source", source); + retObject.insert("target", target); + return retObject; +} diff --git a/src/server/library/sysadm-beadm.h b/src/server/library/sysadm-beadm.h new file mode 100644 index 0000000..488bcf7 --- /dev/null +++ b/src/server/library/sysadm-beadm.h @@ -0,0 +1,23 @@ +//=========================================== +// PC-BSD source code +// Copyright (c) 2015, PC-BSD Software/iXsystems +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#ifndef __PCBSD_LIB_UTILS_BEADM_H +#define __PCBSD_LIB_UTILS_BEADM_H + +#include +#include "sysadm-global.h" + +namespace sysadm{ + +class BEADM{ +public: + static QJsonObject listBEs(); + static QJsonObject renameBE(QJsonObject); +}; + +} //end of pcbsd namespace + +#endif diff --git a/src/server/library/sysadm-iocage.cpp b/src/server/library/sysadm-iocage.cpp index 0b1d872..36c35fa 100644 --- a/src/server/library/sysadm-iocage.cpp +++ b/src/server/library/sysadm-iocage.cpp @@ -12,6 +12,126 @@ using namespace sysadm; //PLEASE: Keep the functions in the same order as listed in pcbsd-general.h +// Clean everything iocage related on a box +QJsonObject Iocage::cleanAll() { + QJsonObject retObject; + + QStringList output = General::RunCommand("iocage clean -fa ").split("\n"); + + for ( int i = 0; i < output.size(); i++) + { + // This means either a mount is stuck or a jail cannot be stopped, + // give them the error. + if ( output.at(i).indexOf("ERROR:") != -1 ) { + retObject.insert("error", output.at(i)); + break; + } else { + // iocage does a spinner for these that is distracting to see returned, + // returning what a user wants to actually see. + retObject.insert("success", "All iocage datasets have been cleaned."); + } + } + + return retObject; +} + +// Clean all templates on a box +QJsonObject Iocage::cleanTemplates() { + QJsonObject retObject; + + QStringList output = General::RunCommand("iocage clean -ft ").split("\n"); + + for ( int i = 0; i < output.size(); i++) + { + // This means either a mount is stuck or a jail cannot be stopped, + // give them the error. + if ( output.at(i).indexOf("ERROR:") != -1 ) { + retObject.insert("error", output.at(i)); + break; + } else { + // iocage does a spinner for these that is distracting to see returned, + // returning what a user wants to actually see. + retObject.insert("success", "All templates have been cleaned."); + } + } + + return retObject; +} + +// Clean all RELEASEs on a box +QJsonObject Iocage::cleanReleases() { + QJsonObject retObject; + + QStringList output = General::RunCommand("iocage clean -fr ").split("\n"); + + for ( int i = 0; i < output.size(); i++) + { + // This means either a mount is stuck or a jail cannot be stopped, + // give them the error. + if ( output.at(i).indexOf("ERROR:") != -1 ) { + retObject.insert("error", output.at(i)); + break; + } else { + // iocage does a spinner for these that is distracting to see returned, + // returning what a user wants to actually see. + retObject.insert("success", "All RELEASEs have been cleaned."); + } + } + + return retObject; +} + +// Clean all jails on a box +QJsonObject Iocage::cleanJails() { + QJsonObject retObject; + + QStringList output = General::RunCommand("iocage clean -fj ").split("\n"); + + for ( int i = 0; i < output.size(); i++) + { + // This means either a mount is stuck or a jail cannot be stopped, + // give them the error. + if ( output.at(i).indexOf("ERROR:") != -1 ) { + retObject.insert("error", output.at(i)); + break; + } else { + // iocage does a spinner for these that is distracting to see returned, + // returning what a user wants to actually see. + retObject.insert("success", "All jails have been cleaned."); + } + } + + return retObject; +} + +// Resource cap a jail on the box +QJsonObject Iocage::capJail(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 = General::RunCommand("iocage cap " + jail).split("\n"); + QJsonObject vals; + + for ( int i = 0; i < output.size(); i++) + { + if ( ! output.at(i).isEmpty()) + break; + + // When a cap is successful, iocage doesn't return anything, so we have to + // fudge the output a bit. + retObject.insert("success", "jail " + jail + " capped."); + } + + return retObject; +} + // Deactivate a zpool for iocage on the box QJsonObject Iocage::deactivatePool(QJsonObject jsin) { QJsonObject retObject; diff --git a/src/server/library/sysadm-iocage.h b/src/server/library/sysadm-iocage.h index 9c13dcf..0497f16 100644 --- a/src/server/library/sysadm-iocage.h +++ b/src/server/library/sysadm-iocage.h @@ -14,6 +14,11 @@ namespace sysadm{ class Iocage{ public: + static QJsonObject cleanAll(); + static QJsonObject cleanTemplates(); + static QJsonObject cleanReleases(); + static QJsonObject cleanJails(); + static QJsonObject capJail(QJsonObject); static QJsonObject deactivatePool(QJsonObject); static QJsonObject activatePool(QJsonObject); static QJsonObject stopJail(QJsonObject); diff --git a/src/server/library/sysadm-iohyve.cpp b/src/server/library/sysadm-iohyve.cpp index 0b3213b..739d3f2 100644 --- a/src/server/library/sysadm-iohyve.cpp +++ b/src/server/library/sysadm-iohyve.cpp @@ -4,14 +4,43 @@ // Available under the 3-clause BSD license // See the LICENSE file for full details //=========================================== +#include #include "sysadm-general.h" #include "sysadm-iohyve.h" #include "sysadm-global.h" +#include "globals.h" using namespace sysadm; //PLEASE: Keep the functions in the same order as listed in pcbsd-general.h +// Queue the fetch of an ISO +QJsonObject Iohyve::fetchISO(QJsonObject jsin) { + QJsonObject retObject; + + QStringList keys = jsin.keys(); + if (! keys.contains("url") ) { + retObject.insert("error", "Missing required key 'url'"); + return retObject; + } + + // Get the key values + QString url = jsin.value("url").toString(); + + // Create a unique ID for this queued action + QString ID = QUuid::createUuid().toString(); + + // Queue the fetch action + DISPATCHER->queueProcess(ID, "iohyve fetch " + url); + + // Return some details to user that the action was queued + retObject.insert("command", "iohyve fetch " + url); + retObject.insert("comment", "Task Queued"); + retObject.insert("queueid", ID); + return retObject; +} + + // List the VMs on the box QJsonObject Iohyve::listVMs() { QJsonObject retObject; @@ -40,3 +69,57 @@ QJsonObject Iohyve::listVMs() { return retObject; } + +// Rename an ISO file +QJsonObject Iohyve::renameISO(QJsonObject jsin) { + QJsonObject retObject; + + QStringList keys = jsin.keys(); + if (! keys.contains("source") || ! keys.contains("target") ) { + retObject.insert("error", "Missing required key(s) 'source / target'"); + return retObject; + } + + // Get the key values + QString source = jsin.value("source").toString(); + QString target = jsin.value("target").toString(); + + QStringList output = General::RunCommand("iohyve renameiso " + source + " " + target).split("\n"); + for ( int i = 0; i < output.size(); i++) + { + if ( output.at(i).indexOf("cannot open") != -1 ) { + retObject.insert("error", output.at(i)); + return retObject; + } + } + + retObject.insert("source", source); + retObject.insert("target", target); + return retObject; +} + +// Remove an ISO file +QJsonObject Iohyve::rmISO(QJsonObject jsin) { + QJsonObject retObject; + + QStringList keys = jsin.keys(); + if (! keys.contains("target") ) { + retObject.insert("error", "Missing required key 'target'"); + return retObject; + } + + // Get the key values + QString target = jsin.value("target").toString(); + + QStringList output = General::RunCommand("iohyve rmiso " + target).split("\n"); + for ( int i = 0; i < output.size(); i++) + { + if ( output.at(i).indexOf("cannot open") != -1 ) { + retObject.insert("error", output.at(i)); + return retObject; + } + } + retObject.insert("target", target); + return retObject; +} + diff --git a/src/server/library/sysadm-iohyve.h b/src/server/library/sysadm-iohyve.h index 7dec2fc..292397e 100644 --- a/src/server/library/sysadm-iohyve.h +++ b/src/server/library/sysadm-iohyve.h @@ -14,7 +14,10 @@ namespace sysadm{ class Iohyve{ public: + static QJsonObject fetchISO(QJsonObject); static QJsonObject listVMs(); + static QJsonObject renameISO(QJsonObject); + static QJsonObject rmISO(QJsonObject); }; } //end of pcbsd namespace diff --git a/src/server/library/sysadm-lifepreserver.cpp b/src/server/library/sysadm-lifepreserver.cpp index 0884fdb..d495b02 100644 --- a/src/server/library/sysadm-lifepreserver.cpp +++ b/src/server/library/sysadm-lifepreserver.cpp @@ -127,7 +127,7 @@ QJsonObject LifePreserver::initReplication(QJsonObject jsin) { QJsonObject LifePreserver::listCron() { QJsonObject retObject; - QStringList output = General::RunCommand("lpreserver listcron").split("\n"); + QStringList output = General::RunCommand("lpreserver cronsnap list").split("\n"); QList snaps; // Parse the output @@ -254,7 +254,7 @@ QJsonObject LifePreserver::listSnap(QJsonObject jsin) { return retObject; } - QStringList output = General::RunCommand("lpreserver listsnap " + pool ).split("\n"); + QStringList output = General::RunCommand("lpreserver snapshot list " + pool ).split("\n"); QList snaps; QStringList snapitems; QRegExp sep("\\s+"); @@ -350,7 +350,7 @@ QJsonObject LifePreserver::removeSnapshot(QJsonObject jsin) { } QStringList output; - output = General::RunCommand("lpreserver rmsnap " + dataset + " " + snap).split("\n"); + output = General::RunCommand("lpreserver snapshot remove " + dataset + " " + snap).split("\n"); // Check for any errors for ( int i = 0; i < output.size(); i++) @@ -426,7 +426,7 @@ QJsonObject LifePreserver::revertSnapshot(QJsonObject jsin) { } QStringList output; - output = General::RunCommand("lpreserver revertsnap " + dataset + " " + snap).split("\n"); + output = General::RunCommand("lpreserver snapshot revert " + dataset + " " + snap).split("\n"); // Check for any errors for ( int i = 0; i < output.size(); i++) @@ -589,9 +589,9 @@ QJsonObject LifePreserver::scheduleSnapshot(QJsonObject jsin) { QStringList output; if ( frequency == "none" ) - output = General::RunCommand("lpreserver cronsnap " + pool + " stop " ).split("\n"); + output = General::RunCommand("lpreserver cronsnap stop " + pool ).split("\n"); else - output = General::RunCommand("lpreserver cronsnap " + pool + " start " + frequency + " " + keep ).split("\n"); + output = General::RunCommand("lpreserver cronsnap start " + pool + " " + frequency + " " + keep ).split("\n"); // Check for any errors for ( int i = 0; i < output.size(); i++) diff --git a/tests/api-test.sh b/tests/api-test.sh index a4641ba..ccf7b8a 100755 --- a/tests/api-test.sh +++ b/tests/api-test.sh @@ -2,12 +2,30 @@ # (Yes, yes, this is a bash script) # Both resty/jsawk use bash'isms +# Possible environment variables +# APITESTUSER - username +# APITESTPASS - password +# APITESTNAMESPACE - namespace / sysadm +# APITESTCLASS - API class +# APITESTPAYLOAD - JSON payload + +# Default values +DEFUSER="root" +DEFNAMESPACE="sysadm" +DEFCLASS="lifepreserver" + # Set variable to call jsawk utility JSAWK="./utils/jsawk -j js24" +if [ `id -u` != "0" ] ; then + pkgPre="sudo" +else + pkgPre="" +fi + which npm >/dev/null 2>/dev/null if [ $? -ne 0 ] ; then - pkg install -y npm + $pkgPre pkg install -y npm if [ $? -ne 0 ] ; then echo "Requires npm!" exit 1 @@ -16,7 +34,7 @@ fi pkg info p5-JSON >/dev/null 2>/dev/null if [ $? -ne 0 ] ; then - pkg install -y p5-JSON + $pkgPre pkg install -y p5-JSON if [ $? -ne 0 ] ; then echo "Requires p5-JSON!" exit 1 @@ -39,75 +57,96 @@ if [ ! -d "${HOME}/.npm/wss" ] ; then fi fi -echo "Enter your username:" -echo -e ">\c" -read fuser -echo "" - -echo "Enter your password:" -echo -e ">\c" -read -s fpass -echo "" - -echo "Enter the namespace:" -echo -e "(sysadm)>\c" -read namesp -if [ -z "$namesp" ] ; then - namesp="sysadm" +if [ -z "$APITESTUSER" ] ; then + echo "Enter your username:" + echo -e "($DEFUSER)>\c" + read APITESTUSER + if [ -z "$APITESTUSER" ] ; then + APITESTUSER="$DEFUSER" + fi + echo "" fi -echo "" -echo "Enter the class name:" -echo -e "(lifepreserver)>\c" -read name -if [ -z "$name" ] ; then - name="lifepreserver" +if [ -z "$APITESTPASS" ] ; then + echo "Enter your password:" + echo -e ">\c" + read -s APITESTPASS + echo "" fi -echo "" -echo "Enter the payload json:" -echo -e "{ \"action\":\"listcron\" }>\c" -read payload -if [ -z "$payload" ] ; then - payload="{ \"action\":\"listcron\" }" +if [ -z "$APITESTNAMESPACE" ] ; then + echo "Enter the namespace:" + echo -e "($DEFNAMESPACE)>\c" + read APITESTNAMESPACE + if [ -z "$APITESTNAMESPACE" ] ; then + APITESTNAMESPACE="$DEFNAMESPACE" + fi + echo "" +fi + +if [ -z "$APITESTCLASS" ] ; then + echo "Enter the class name:" + echo -e "($DEFCLASS)>\c" + read APITESTCLASS + if [ -z "$APITESTCLASS" ] ; then + APITESTCLASS="$DEFCLASS" + fi + echo "" +fi + +if [ -z "$APITESTPAYLOAD" ] ; then + echo "Enter the payload json:" + echo -e "{ \"action\":\"listcron\" }>\c" + read APITESTPAYLOAD + if [ -z "$APITESTPAYLOAD" ] ; then + APITESTPAYLOAD="{ \"action\":\"listcron\" }" + fi + echo "" fi -echo "" # Source our resty functions -. ./utils/resty -W "https://127.0.0.1:12151" -H "Accept: application/json" -H "Content-Type: application/json" -u ${fuser}:${fpass} +#. ./utils/resty -W "https://127.0.0.1:12151" -H "Accept: application/json" -H "Content-Type: application/json" -u ${fuser}:${fpass} # Save output to a file in addition to stdout -ofile="/tmp/api-response" -echo "" > /tmp/api-response +#ofile="/tmp/api-response" +#echo "" > /tmp/api-response # Check the reply of this REST query -echo "" | tee -a $ofile -echo "REST Request:" | tee -a $ofile -echo "-------------------------------" | tee -a $ofile -echo "PUT /${namesp}/${name}" | tee -a $ofile -echo "${payload}" | perl -0007 -MJSON -ne'print to_json(from_json($_, {allow_nonref=>1}),{pretty=>1})."\n"' | tee -a $ofile +#echo "" | tee -a $ofile +#echo "REST Request:" | tee -a $ofile +#echo "-------------------------------" | tee -a $ofile +#echo "PUT /${namesp}/${name}" | tee -a $ofile +#echo "${payload}" | perl -0007 -MJSON -ne'print to_json(from_json($_, {allow_nonref=>1}),{pretty=>1})."\n"' | tee -a $ofile -echo "" | tee -a $ofile -echo "REST Response:" | tee -a $ofile -echo "-------------------------------" | tee -a $ofile -PUT /${namesp}/${name} "${payload}" -v -k 2>/tmp/.rstErr | tee -a $ofile -if [ $? -ne 0 ] ; then - echo "Failed.. Error output:" - cat /tmp/.rstErr -fi -rm $ofile -rm /tmp/.rstErr +#echo "" | tee -a $ofile +#echo "REST Response:" | tee -a $ofile +#echo "-------------------------------" | tee -a $ofile +#PUT /${namesp}/${name} "${payload}" -v -k 2>/tmp/.rstErr | tee -a $ofile +#if [ $? -ne 0 ] ; then +# echo "Failed.. Error output:" +# cat /tmp/.rstErr +#fi +#rm $ofile +#rm /tmp/.rstErr # Now check the response via WebSockets export NODE_TLS_REJECT_UNAUTHORIZED=0 +rm $ofile >/dev/null 2>/dev/null +ofile="/tmp/api-response" +echo "" > $ofile + +echo "REST Request:" | tee -a $ofile +echo "-------------------------------" | tee -a $ofile +echo "PUT /${APITESTNAMESPACE}/${APITESTCLASS}" | tee -a $ofile +echo "${APITESTPAYLOAD}" | perl -0007 -MJSON -ne'print to_json(from_json($_, {allow_nonref=>1}),{pretty=>1})."\n"' | tee -a $ofile + echo "" | tee -a $ofile echo "WebSocket Request:" | tee -a $ofile echo "-------------------------------" | tee -a $ofile -echo "{ \"namespace\":\"${namesp}\", \"name\":\"${name}\", \"id\":\"fooid\", \"args\":${payload} }" | perl -0007 -MJSON -ne'print to_json(from_json($_, {allow_nonref=>1}),{pretty=>1})."\n"' | tee -a $ofile +echo "{ \"namespace\":\"${APITESTNAMESPACE}\", \"name\":\"${APITESTCLASS}\", \"id\":\"fooid\", \"args\":${APITESTPAYLOAD} }" | perl -0007 -MJSON -ne'print to_json(from_json($_, {allow_nonref=>1}),{pretty=>1})."\n"' | tee -a $ofile echo "" | tee -a $ofile -echo "WebSocket Response:" | tee -a $ofile +echo "Response:" | tee -a $ofile echo "-------------------------------" | tee -a $ofile -echo "{ \"namespace\":\"${namesp}\", \"name\":\"${name}\", \"id\":\"fooid\", \"args\":${payload} }" | node sendwebsocket.js "$fuser" "$fpass" | tee -a $ofile -rm $ofile +echo "{ \"namespace\":\"${APITESTNAMESPACE}\", \"name\":\"${APITESTCLASS}\", \"id\":\"fooid\", \"args\":${APITESTPAYLOAD} }" | node sendwebsocket.js "$APITESTUSER" "$APITESTPASS" | tee -a $ofile