diff options
-rw-r--r-- | poetry.lock | 77 | ||||
-rw-r--r-- | pyproject.toml | 1 | ||||
-rw-r--r-- | rwa/support/sessionservice/config.py | 5 | ||||
-rwxr-xr-x | rwa/support/sessionservice/service.py | 74 | ||||
-rw-r--r-- | rwa/support/sessionservice/session.py | 28 | ||||
-rwxr-xr-x | test_client.py | 3 |
6 files changed, 138 insertions, 50 deletions
diff --git a/poetry.lock b/poetry.lock index ff5ea5b..0c0a1a8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -8,7 +8,7 @@ python-versions = "*" [[package]] name = "aleksis-builddeps" -version = "2021.6b0" +version = "2021.6rc2" description = "AlekSIS (School Information System) — Build/Dev dependencies for apps" category = "dev" optional = false @@ -46,7 +46,7 @@ sphinxcontrib-django = ">=0.5.0,<0.6.0" name = "appdirs" version = "1.4.4" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" +category = "main" optional = false python-versions = "*" @@ -60,7 +60,7 @@ python-versions = "*" [[package]] name = "asgiref" -version = "3.3.4" +version = "3.4.0" description = "ASGI specs, helper code, and adapters" category = "dev" optional = false @@ -518,7 +518,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "4.5.0" +version = "4.6.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -530,7 +530,8 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +perf = ["ipython"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" @@ -556,25 +557,25 @@ plugins = ["setuptools"] [[package]] name = "itsdangerous" -version = "1.1.0" -description = "Various helpers to pass data to untrusted environments and back." +version = "2.0.1" +description = "Safely pass data to untrusted environments and back." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [[package]] name = "jinja2" -version = "2.11.3" +version = "3.0.1" description = "A very fast and expressive template engine." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" [package.dependencies] -MarkupSafe = ">=0.23" +MarkupSafe = ">=2.0" [package.extras] -i18n = ["Babel (>=0.8)"] +i18n = ["Babel (>=2.7)"] [[package]] name = "markupsafe" @@ -1206,7 +1207,7 @@ python-versions = "*" [[package]] name = "urllib3" -version = "1.26.5" +version = "1.26.6" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false @@ -1218,6 +1219,17 @@ secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "cer socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] +name = "usersettings" +version = "1.1.5" +description = "Portable Local Settings Storage" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +appdirs = ">=1.2" + +[[package]] name = "websockify" version = "0.9.0" description = "Websockify." @@ -1230,14 +1242,13 @@ numpy = "*" [[package]] name = "werkzeug" -version = "1.0.1" +version = "2.0.1" description = "The comprehensive WSGI web application library." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" [package.extras] -dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"] watchdog = ["watchdog"] [[package]] @@ -1255,7 +1266,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "acbf56b1d53e7831a6325e327dbcdfc4fcaff60ab07eb5862d6bdb6807ef4132" +content-hash = "e94d233aff281e3b0cdf43eab46ee628f6772a88780ca76396f008ae41fb4548" [metadata.files] alabaster = [ @@ -1263,8 +1274,8 @@ alabaster = [ {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, ] aleksis-builddeps = [ - {file = "AlekSIS-Builddeps-2021.6b0.tar.gz", hash = "sha256:a70b4d917e0f03d037384960f108b13d9b0413cc082b171f2f239163fd93462a"}, - {file = "AlekSIS_Builddeps-2021.6b0-py3-none-any.whl", hash = "sha256:b579c9e2938179c83d3e2656cdc5c28ea9113be65498b8e8ea7f380b6783154b"}, + {file = "AlekSIS-Builddeps-2021.6rc2.tar.gz", hash = "sha256:abefdf307dbc2ec3e4e1688f59621bb0da80911b248cc0ed6fb04de5d0fbf641"}, + {file = "AlekSIS_Builddeps-2021.6rc2-py3-none-any.whl", hash = "sha256:4290c265a90bd96c093da413905641888d33dc55d0e34512d057cd53d5c40977"}, ] appdirs = [ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, @@ -1275,8 +1286,8 @@ argparse = [ {file = "argparse-1.4.0.tar.gz", hash = "sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4"}, ] asgiref = [ - {file = "asgiref-3.3.4-py3-none-any.whl", hash = "sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee"}, - {file = "asgiref-3.3.4.tar.gz", hash = "sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"}, + {file = "asgiref-3.4.0-py3-none-any.whl", hash = "sha256:d36fa91dd90e3aa3c81a6bd426ccc8fb20bd3d22b0cf14a12800289e9c3e2563"}, + {file = "asgiref-3.4.0.tar.gz", hash = "sha256:05914d0fa65a21711e732adc6572edad6c8da5f1435c3f0c060689ced5e85195"}, ] asn1crypto = [ {file = "asn1crypto-1.4.0-py2.py3-none-any.whl", hash = "sha256:4bcdf33c861c7d40bdcd74d8e4dd7661aac320fcdf40b9a3f95b4ee12fde2fa8"}, @@ -1475,8 +1486,8 @@ imagesize = [ {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.5.0-py3-none-any.whl", hash = "sha256:833b26fb89d5de469b24a390e9df088d4e52e4ba33b01dc5e0e4f41b81a16c00"}, - {file = "importlib_metadata-4.5.0.tar.gz", hash = "sha256:b142cc1dd1342f31ff04bb7d022492b09920cb64fed867cd3ea6f80fe3ebd139"}, + {file = "importlib_metadata-4.6.0-py3-none-any.whl", hash = "sha256:c6513572926a96458f8c8f725bf0e00108fba0c9583ade9bd15b869c9d726e33"}, + {file = "importlib_metadata-4.6.0.tar.gz", hash = "sha256:4a5611fea3768d3d967c447ab4e93f567d95db92225b43b7b238dbfb855d70bb"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -1487,12 +1498,12 @@ isort = [ {file = "isort-5.9.1.tar.gz", hash = "sha256:83510593e07e433b77bd5bff0f6f607dbafa06d1a89022616f02d8b699cfcd56"}, ] itsdangerous = [ - {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"}, - {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"}, + {file = "itsdangerous-2.0.1-py3-none-any.whl", hash = "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c"}, + {file = "itsdangerous-2.0.1.tar.gz", hash = "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"}, ] jinja2 = [ - {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, - {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, + {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, + {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, ] markupsafe = [ {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, @@ -1927,15 +1938,19 @@ typing-extensions = [ {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, ] urllib3 = [ - {file = "urllib3-1.26.5-py2.py3-none-any.whl", hash = "sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c"}, - {file = "urllib3-1.26.5.tar.gz", hash = "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"}, + {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, + {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"}, +] +usersettings = [ + {file = "usersettings-1.1.5-py3-none-any.whl", hash = "sha256:503be61d30d0cfd98f16bb6c9be86c29e78dc476c794ffae6333ab26f38994bf"}, + {file = "usersettings-1.1.5.tar.gz", hash = "sha256:9f84b282982622d8ebfd2d42b482317ae50fb2b3a7fba22e0b0c36cac61ad673"}, ] websockify = [ {file = "websockify-0.9.0.tar.gz", hash = "sha256:c35b5b79ebc517d3b784dacfb993be413a93cda5222c6f382443ce29c1a6cada"}, ] werkzeug = [ - {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"}, - {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"}, + {file = "Werkzeug-2.0.1-py3-none-any.whl", hash = "sha256:6c1ec500dcdba0baa27600f6a22f6333d8b662d22027ff9f6202e3367413caa8"}, + {file = "Werkzeug-2.0.1.tar.gz", hash = "sha256:1de1db30d010ff1af14a009224ec49ab2329ad2cde454c8a708130642d579c42"}, ] zipp = [ {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, diff --git a/pyproject.toml b/pyproject.toml index 88e529b..de0b661 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ psutil = "^5.7.2" flask = "^1.1.2" argparse = "^1.0.10" dynaconf = "^3.0.0" +usersettings = "^1.1.5" click = "^8.0.1" [tool.poetry.dev-dependencies] diff --git a/rwa/support/sessionservice/config.py b/rwa/support/sessionservice/config.py index f0f8369..4f39a4e 100644 --- a/rwa/support/sessionservice/config.py +++ b/rwa/support/sessionservice/config.py @@ -23,8 +23,13 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. +import usersettings from dynaconf import Dynaconf settings = Dynaconf( envvar_prefix="RWA", settings_files=["/etc/rwa/support/sessionservice/settings.toml"] ) + +user_settings = usersettings.Settings("org.ArcticaProject.RWASupportSessionService") +user_settings.add_setting("web_app_hosts", list, ["http://127.0.0.1:8000"]) +user_settings.load_settings() diff --git a/rwa/support/sessionservice/service.py b/rwa/support/sessionservice/service.py index 3e9900d..2bc727d 100755 --- a/rwa/support/sessionservice/service.py +++ b/rwa/support/sessionservice/service.py @@ -38,6 +38,7 @@ import dbus.mainloop.glib import dbus.service from gi.repository import GLib +from .config import user_settings from .lock import is_locked, lock, unlock from .session import Session from .trigger import TriggerServerThread @@ -76,10 +77,73 @@ class RWASupportSessionService(dbus.service.Object): logging.info("D-Bus service has been started.") + def _get_web_app_hosts(self) -> str: + """Get all registered RWA.Support.WebApp hosts. + + Helper function: No D-Bus API. + """ + hosts = user_settings.web_app_hosts + return json.dumps(hosts) + @dbus.service.method("org.ArcticaProject.RWASupportSessionService", out_signature="s") - def start(self) -> str: + def get_web_app_hosts(self) -> str: + """Get all registered RWA.Support.WebApp hosts. + + :return: All registered hosts as JSON array (D-Bus string) + + **Structure of returned JSON:** + + :: + + ["https://example.org", "http://127.0.0.1:8000"] + """ + return self._get_web_app_hosts() + + @dbus.service.method( + "org.ArcticaProject.RWASupportSessionService", in_signature="s", out_signature="s" + ) + def add_web_app_host(self, host: str) -> str: + """Add a RWA.Support.WebApp host. + + :param host: Exact hostname of the RWA.Support.WebApp host (D-Bus string) + :return: All registered hosts as JSON array (D-Bus string) + + **Structure of returned JSON:** + + :: + + ["https://example.org", "http://127.0.0.1:8000"] + """ + user_settings.web_app_hosts.append(host) + user_settings.save_settings() + return self._get_web_app_hosts() + + @dbus.service.method( + "org.ArcticaProject.RWASupportSessionService", in_signature="i", out_signature="s" + ) + def remove_web_app_host(self, idx: int) -> str: + """Remove a RWA.Support.WebApp host. + + :param idx: Index of web app host (D-Bus integer) + :return: All registered hosts as JSON array (D-Bus string) + + **Structure of returned JSON:** + + :: + + ["https://example.org", "http://127.0.0.1:8000"] + """ + del user_settings.web_app_hosts[idx] + user_settings.save_settings() + return self._get_web_app_hosts() + + @dbus.service.method( + "org.ArcticaProject.RWASupportSessionService", in_signature="i", out_signature="s" + ) + def start(self, host_idx: int) -> str: """Start a new remote session and register it in RWA.Support.WebApp. + :param host_idx: Index of web app host (D-Bus integer) :return: Result as JSON (D-Bus string) **Structure of returned JSON (success):** @@ -103,10 +167,16 @@ class RWASupportSessionService(dbus.service.Object): "session, so this session won't be started." ) return json.dumps({"status": "error", "type": "multiple"}) + print(host_idx, user_settings.web_app_hosts) + + try: + host = user_settings.web_app_hosts[host_idx] + except IndexError: + return json.dumps({"status": "error", "type": "host_not_found"}) # Start session try: - session = Session(self.trigger_service.port, self.mockup_mode) + session = Session(host, self.trigger_service.port, self.mockup_mode) # Add session to sessions list self.sessions[session.pid] = session diff --git a/rwa/support/sessionservice/session.py b/rwa/support/sessionservice/session.py index cabef5f..11c418e 100644 --- a/rwa/support/sessionservice/session.py +++ b/rwa/support/sessionservice/session.py @@ -35,20 +35,10 @@ import port_for import psutil import requests -from .config import settings from .lock import TEMP_DIR_PATH from .log import logging from .vnc import run_vnc, save_password -API_SERVER = settings.get("api_url", "http://127.0.0.1") -BASE_URL = API_SERVER + "/app/rwasupport/api/" -REGISTER_URL = BASE_URL + "register/" -STOP_URL = BASE_URL + "stop/" -STATUS_URL = BASE_URL + "status/" -MARK_JOB_AS_DONE_URL = BASE_URL + "jobs/mark_as_done/" - -logging.info(f"Load API config: {API_SERVER}") - def random_digits(length: int): return "".join(secrets.choice(string.digits) for _ in range(length)) @@ -67,7 +57,15 @@ class Session: #: Remote has joined the session STATUS_JOINED = "active" - def __init__(self, trigger_port: int, mockup_session: bool = False): + def __init__(self, host: str, trigger_port: int, mockup_session: bool = False): + self.host = host + self.BASE_URL = self.host + "/app/rwasupport/api/" + self.REGISTER_URL = self.BASE_URL + "register/" + self.STOP_URL = self.BASE_URL + "stop/" + self.STATUS_URL = self.BASE_URL + "status/" + self.MARK_JOB_AS_DONE_URL = self.BASE_URL + "jobs/mark_as_done/" + logging.info(f"Load API config: {self.host}") + self.trigger_token = secrets.token_urlsafe(20) self.trigger_port = trigger_port self.done_jobs = [] @@ -136,7 +134,7 @@ class Session: if not self.mockup_session: try: r = requests.post( - REGISTER_URL, + self.REGISTER_URL, json={ "port": self.ws_port, "pid": self.vnc_pid, @@ -187,7 +185,7 @@ class Session: if not self.mockup_session: try: r = requests.get( - STATUS_URL, params={"id": self.session_id}, headers=self._api_headers + self.STATUS_URL, params={"id": self.session_id}, headers=self._api_headers ) logging.info( @@ -224,7 +222,7 @@ class Session: self.done_jobs.append(job["job_id"]) try: r = requests.post( - MARK_JOB_AS_DONE_URL, params={"id": job["job_id"]}, headers=self._api_headers, + self.MARK_JOB_AS_DONE_URL, params={"id": job["job_id"]}, headers=self._api_headers, ) logging.info( f"The session has marked the job {job} as done in RWA.Support.WebApp " @@ -268,7 +266,7 @@ class Session: if not triggered: try: r = requests.post( - STOP_URL, params={"id": self.session_id}, headers=self._api_headers + self.STOP_URL, params={"id": self.session_id}, headers=self._api_headers ) logging.info( "The stop action has been registered in RWA.Support.WebApp " diff --git a/test_client.py b/test_client.py index 9e2f15c..5176ad2 100755 --- a/test_client.py +++ b/test_client.py @@ -43,7 +43,7 @@ def cli(): def start(host: int): """Start a session on the RWA.Support.WebApp host with index HOST.""" click.echo(f"Sending D-Bus request 'start': {host}") - response = req.start() + response = req.start(host) click.echo(f"Your response is: {response}") @@ -73,6 +73,5 @@ def refresh_status(pid: int): response = req.refresh_status(pid) click.echo(f"Your response is: {response}") - if __name__ == "__main__": cli() |