diff --git a/app/core/config.py b/app/core/config.py index 3ae3278..3ade2fa 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -88,8 +88,15 @@ class Settings(BaseSettings): db_file: str = "sqlite:///./flux-restful.db" flux_user: str = os.environ.get("FLUX_USER") or "fluxuser" flux_token: Optional[str] = os.environ.get("FLUX_TOKEN") + flux_server_mode: Optional[str] = ( + os.environ.get("FLUX_SERVER_MODE") or "single-user" + ) secret_key: str = os.environ.get("FLUX_SECRET_KEY") or generate_secret_key() + # Validate the server mode provided. + if flux_server_mode not in ["single-user", "multi-user"]: + raise ValueError("FLUX_SERVER_MODE must be single-user or multi-user") + # Expires in 10 hours access_token_expires_minutes: int = get_int_envar( "FLUX_ACCESS_TOKEN_EXPIRES_MINUTES", 600 diff --git a/app/library/auth.py b/app/library/auth.py index 4b0c357..afd9b62 100644 --- a/app/library/auth.py +++ b/app/library/auth.py @@ -23,6 +23,7 @@ def not_authenticated(detail="Incorrect user or token."): def alert_auth(): print("🍓 Require auth: %s" % settings.require_auth) + print("🍓 Server mode: %s" % settings.flux_server_mode) print( "🍓 Secret key %s" % ("*" * len(settings.secret_key)) if settings.secret_key diff --git a/app/library/flux.py b/app/library/flux.py index 4f4b0c6..d00b76e 100644 --- a/app/library/flux.py +++ b/app/library/flux.py @@ -33,8 +33,8 @@ def submit_job(handle, fluxjob, user): elif user and isinstance(user, str): print(f"User submitting job {user}") - # If we don't have auth enabled, submit in single-user mode - if not settings.require_auth: + # If we don't have auth enabled or request is for single-user mode + if not settings.require_auth or settings.flux_server_mode == "single-user": print("Submit in single-user mode.") return flux.job.submit_async(handle, fluxjob) diff --git a/clients/python/CHANGELOG.md b/clients/python/CHANGELOG.md index e0e4b82..ced0165 100644 --- a/clients/python/CHANGELOG.md +++ b/clients/python/CHANGELOG.md @@ -14,6 +14,8 @@ and **Merged pull requests**. Critical items to know are: The versions coincide with releases on pip. Only major versions will be released as tags on Github. ## [0.0.x](https://github.com/flux-framework/flux-restful-api/tree/main) (0.0.x) + - Fix bug with submit and POST needing params (0.2.1) + - New release with updated client (0.2.0) - Update to use newer versions of fastapi, etc (0.1.15) - option_flags is a flat string list of values - Expose host to environment and bug fix for logs (0.1.14) diff --git a/clients/python/flux_restful_client/main/client.py b/clients/python/flux_restful_client/main/client.py index d0fdda3..0498235 100644 --- a/clients/python/flux_restful_client/main/client.py +++ b/clients/python/flux_restful_client/main/client.py @@ -104,6 +104,7 @@ def do_request( headers = headers or self.headers url = f"{self.host}/{self.prefix}/{endpoint}" + method = method.upper() # Make the request and return to calling function, unless requires auth try: @@ -111,7 +112,7 @@ def do_request( response = self.session.stream( method, url, json=data, params=params, headers=headers ) - if method == "POST": + elif method == "POST": response = self.session.post(url, params=data, headers=headers) elif method == "GET" and stream: response = self.session.stream( diff --git a/clients/python/flux_restful_client/version.py b/clients/python/flux_restful_client/version.py index c811bf6..3055578 100644 --- a/clients/python/flux_restful_client/version.py +++ b/clients/python/flux_restful_client/version.py @@ -1,4 +1,4 @@ -__version__ = "0.2.0" +__version__ = "0.2.1" AUTHOR = "Vanessa Sochat" EMAIL = "vsoch@users.noreply.github.com" NAME = "flux-restful-client" diff --git a/docs/getting_started/developer-guide.md b/docs/getting_started/developer-guide.md index 8af5d3c..6bca051 100644 --- a/docs/getting_started/developer-guide.md +++ b/docs/getting_started/developer-guide.md @@ -45,6 +45,7 @@ $ docker run --rm -it -p 5000:5000 ghcr.io/flux-framework/flux-restful-api ``` ```console 🍓 Require auth: True +🍓 Server mode: single-user 🍓 Secret key *********** 🍓 Flux user: ******** 🍓 Flux token: ***** @@ -110,8 +111,8 @@ $ flux start uvicorn app.main:app --host=0.0.0.0 --port=5000 Or do it separately (two commands): ```bash -$ flux start --test-size=4 -$ uvicorn app.main:app --host=0.0.0.0 --port=5000 +flux start --test-size=4 +uvicorn app.main:app --host=0.0.0.0 --port=5000 ``` For the latter, you can also use the Makefile: @@ -195,7 +196,7 @@ The following variables are available (with their defaults): |FLUX_TOKEN| The token password to require for Basic Auth (if `FLUX_REQUIRE_AUTH` is set) | unset | |FLUX_USER| The username to require for Basic Auth (if `FLUX_REQUIRE_AUTH` is set) | unset | |FLUX_HAS_GPU | GPUs are available for the user to request | unset | -|FLUX_NUMBER_NODES| The number of nodes available in the cluster | 1 | +|FLUX_NUMBER_NODES| The number of nodes available (exposed) in the cluster | 1 | |FLUX_OPTION_FLAGS | Option flags to give to flux, in the same format you'd give on the command line | unset | |FLUX_SECRET_KEY | secret key to be shared between user and server (required) | unset | |FLUX_ACCESS_TOKEN_EXPIRES_MINUTES| number of minutes to expire an access token | 600 | diff --git a/docs/getting_started/user-guide.md b/docs/getting_started/user-guide.md index 3240468..cea2f35 100644 --- a/docs/getting_started/user-guide.md +++ b/docs/getting_started/user-guide.md @@ -17,6 +17,19 @@ There are two modes of interaction: - **multi-user mode**: requires authentication via the RESTful API with an encoded payload to request expiring tokens. When authentication is successful, the job is run as the same user on the system on behalf of the flux user. +To control the user mode, you can export it to the environment where you are running the server: + +```bash +# This is the default +export FLUX_SERVER_MODE=single-user + +# This will have the flux user attempt to sign the payload with sudo +export FLUX_SERVER_MODE=multi-user +``` + +Note that the majority of our use cases use single-user mode, so you can expect more bugs / work to be +done with multi-user. + ### Authentication If you choose to deploy without authentication, this is a ⚠️ proceed at your own risk ⚠️ sort of deal.