Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add REST API tool for server and module for client #226

Merged
merged 4 commits into from
Jul 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/Subcommand/Version.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ The follow command options are supported:
gridlabd version check [-v|-q]
~~~

The `check` command determines whether the current version is up to date.
The `check` command determines whether the current version is up to date. If the file `no-version-check` is found in the local folder or in the folder `$HOME/.gridlabd`, then the version check is suppressed. This can significantly speed up short calls to gridlabd.

## `help`

Expand Down
23 changes: 23 additions & 0 deletions docs/Utilities/Rest_client.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[[/Utilities/Rest_client]] -- REST API Client

# Synopsis

Python:

~~~
import rest_client
client = Session()
client.upload(FILENAME,FH)
client.run(COMMAND[,OPTIONS[,...]])
client.files([FOLDER])
client.download(PATHNAME)
client.close()
~~~

# Description

The REST API client provide a convenience class to access a `gridlabd rest_server` running on a local or remote host. By default the client accesses the local host without need to identify the server access token. If you are accessing a remote host, you must specify the `client.URL`, including the access token, e.g., `http://SERVER:PORT/TOKEN`.

# See also

* [[/Utilities/Rest_server]]
41 changes: 41 additions & 0 deletions docs/Utilities/Rest_server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[[/Utilities/Rest_server]] -- GridLAB-D REST API Server

# Synopsis

Shell:
~~~
gridlabd rest_server COMMAND [OPTIONS ...]
~~~

## Commands

* `start`: Start server
* `status`: Show server status
* `stop`: Stop server
* `help`: Show this documentation

## Options

* `-h|--help`: Show this documentation

* `--timeout=INTEGER`: Set the simulation runtime limit in seconds (default None)

* `--retention=INTEGER`: Set the result retention time in seconds (default None)

* `--clean=INTEGER`: Set the retention cleanup interval in seconds (default None)

* `--tmpdir=PATH`: Set the temporary storage folder (default /tmp/gridlabd/rest_server)

* `--maxfile=INTEGER`: Set the maximum upload file s (default is 1GB)

* `--logfile=PATHNAME`: Set the logfile name (default TMPDIR+"/server.log")

* `--ssl_context=STRING`: Set the SSL context per Fla (default is None)

# Description

The GridLAB-D REST server provides gridlabd simulation control through a Flask API. The API Spec can be obtained using the endpoint `/api/spec.html` or `/api/spec.json`.

# See also

* [[/Utilities/Rest_client]]
4 changes: 3 additions & 1 deletion python/requirements.csv
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ CensusData,,,1.15
cfo,,,1.0.1
control,,,0.9.2
docker,,,4.4.4
elevation,,,1.1.2
elevation,,,1.1.3
Fiona,,,1.8.22
flask,,,3.0.3
flask-restful-swagger,,,0.20.1
folium,,,0.12.1
geocoder,,,1.38.1
geopandas,,,0.12.2
Expand Down
1 change: 1 addition & 0 deletions subcommands/gridlabd-version
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ END

function version-check()
{
test -f no-version-check -o -f $HOME/.gridlabd/no-version-check && exit 0
version=$(${BIN} --version)
submitversion=$(echo $version | sed -r 's/.*([0-9]+\.[0-9]+\.[0-9]+\-[0-9]+)/\1/')
branch=$(${BIN} --version=git-branch)
Expand Down
4 changes: 4 additions & 0 deletions tools/Makefile.mk
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,8 @@ dist_pkgdata_DATA += tools/noaa_forecast.py
dist_pkgdata_DATA += tools/nsrdb_weather.py
dist_pkgdata_DATA += tools/pole_analysis.py
dist_pkgdata_DATA += tools/read_dlp.py
dist_pkgdata_DATA += tools/rest_client.py
dist_pkgdata_DATA += tools/rest_server.py
dist_pkgdata_DATA += tools/rest_server_config.py
dist_pkgdata_DATA += tools/ucar_weather.py

115 changes: 115 additions & 0 deletions tools/rest_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"""GridLAB-D REST API Client
"""

import os, sys
import json
import requests
import random
from datetime import datetime

try:
from rest_server_config import TMPDIR
except:
TMPDIR="/tmp/gridlabd/rest_server"

def get_server_info():
"""Get server info"""
try:
with open(os.path.join(TMPDIR,"server.info"),"r") as fh:
return json.load(fh)
except FileExistsError:
return None

def server_get(*args,**kwargs):
"""Server GET query"""
req = requests.get(os.path.join(URL,*args),**kwargs)
if req.status_code != 200:
raise Exception(f"HTTP error {req.status_code}")
data = json.loads(req.content.decode('utf-8'))
if data["status"] != "OK":
raise Exception(data["message"])
return data["content"]

def server_post(*args,**kwargs):
"""Server POST query"""
req = requests.post(os.path.join(URL,*args),files=kwargs)
if req.status_code != 200:
raise Exception(f"HTTP error {req.status_code}")
data = json.loads(req.content.decode('utf-8'))
if data["status"] != "OK":
raise Exception(data["message"])
return data["content"]

URL = get_server_info()["url"]

class Session:
"""Session client implementation"""
def __init__(self,session=None):
"""Open session

Parameters:

session (hex): Session id (None for new)
"""
self.sid = session if session else hex(random.randint(1,2**32))[2:]
self.status = server_get(self.sid,"open")
self.created_on = datetime.now()

def close(self):
"""Close session"""
return server_get(self.sid,"close")

def run(self,*args,**kwargs):
"""Run command

Parameters:

*args (str list): gridlabd command
**kwargs (str list): requests GET options
"""
return server_get(self.sid,"run"," ".join(args),**kwargs)

def files(self,path=""):
"""Get list of files

Parameters:

path (str): folder to list (default "")
"""
return server_get(self.sid,"files",path)

def download(self,*args):
"""Download a file

Parameters:

*args (str list): file name to download
"""
result = {}
for file in args:
result[file] = server_get(self.sid,"download",file)
return result

def upload(self,name,fh):
"""Upload a file

Parameters:

name (str): file name to upload

fh (file handle): open file handle
"""
kwargs = {name:fh}
return server_post(self.sid,"upload",**kwargs)

if __name__ == "__main__":

session = Session()
print("Session",session.sid,"created on",session.created_on,"status",session.status)
print(session.upload("test.txt",open("rest_client.py","r")))
print(session.run("version"))
print(session.files())
print(session.download("stdout"))
print(session.download("stderr"))
print(session.download("test.txt"))
print(session.close())
Loading
Loading