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 api key support to python client + server #8

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,21 @@ If the port is different, you can pass the port as the `image_port` argument to
Given you have a model class called `MyModel` in a package `mypackage` then the web service can be started with the following command.

```shell
BMI_MODULE=mypackage BMI_CLASS=MyModel run-bmi-server
BMI_MODULE=mypackage BMI_CLASS=MyModel BMI_API_KEY=somesecret run-bmi-server
```

For example [leakybucket](https://github.com/eWaterCycle/leakybucket-bmi):

```shell
pip install leakybucket
BMI_MODULE=leakybucket.leakybucket_bmi BMI_CLASS=LeakyBucketBmi run-bmi-server
BMI_MODULE=leakybucket.leakybucket_bmi BMI_CLASS=LeakyBucketBmi BMI_API_KEY=somesecret run-bmi-server
```

and the client can connect to it with the following code.

```python
> from remotebmi.client.client import RemoteBmiClient
> client = RemoteBmiClient('http://localhost:50051')
> client = RemoteBmiClient('http://localhost:50051', api_key='somesecret')
> client.get_component_name()
leakybucket
```
Expand Down
5 changes: 5 additions & 0 deletions RemoteBMI.jl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,9 @@ The openapi server stubs where generated using the following command:
```shell
npx @openapitools/openapi-generator-cli generate -i ./openapi.yaml -g julia-server -o julia-server --additional-properties=packageName=BmiServer --additional-properties=exportModels=true
# Copy the generated files to RemoteBMI.jl/src/

# TODO find out why api key is not in the generated code
# At example https://github.com/JuliaComputing/OpenAPI.jl/blob/2d447986b6377a6724ae59380f087c2b270e7795/test/server/openapigenerator_petstore_v3/petstore/src/apis/api_PetApi.jl#L56
# It is given to impl function as second argument
# but in the generated code it is missing
```
10 changes: 6 additions & 4 deletions RemoteBMI.jl/example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dev ..
CTRL-D
# Run server
export BMI_SERVER_PORT=50555
export BMI_SERVER_SECRET="somesecret"
julia --project=$PWD heat_bmi_server.jl
```

Expand All @@ -24,16 +25,17 @@ Interact with it using the Python client.

```python
from remotebmi.client.client import RemoteBmiClient
from remotebmi.client.reserve import reserve_values
from remotebmi.reserve import reserve_values

client = RemoteBmiClient('http://localhost:50555')
# TODO use placeholder for path
# TODO use placeholder for path instead of path on my machine
# client.initialize('<absolute path>/heat.toml')
client.initialize('/home/stefanv/git/eWaterCycle/remotebmi/python/heat.toml')
# TODO Julia server throws error here
client.initialize('/home/verhoes/git/eWaterCycle/remotebmi/python/heat.toml')
# TODO eget_component_name errors because server returns plain/text instead of json
client.get_component_name()
client.update()
client.get_current_time()
client.get_var_type('plate_surface__temperature')
dest = reserve_values(client, 'plate_surface__temperature')
r = client.get_value('plate_surface__temperature', dest)
r
Expand Down
5 changes: 3 additions & 2 deletions RemoteBMI.jl/example/heat_bmi_server.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ using Heat

import RemoteBMI

port = parse(Int, get(ENV, "BMI_PORT", "50051"))
RemoteBMI.run(Heat.Model, "0.0.0.0", port)
port = parse(Int, get(ENV, "BMI_SERVER_PORT", "50051"))
secret = get(ENV, "BMI_SERVER_SECRET", "")
RemoteBMI.run(Heat.Model, "0.0.0.0", port, secret)
15 changes: 8 additions & 7 deletions RemoteBMI.jl/src/BmiServer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ The following server methods must be implemented:
- *signature:* get_grid_size(req::HTTP.Request, grid::Int64;) -> Int64
- **get_grid_type**
- *invocation:* GET /get_grid_type/{grid}
- *signature:* get_grid_type(req::HTTP.Request, grid::Int64;) -> BmiGetGridTypeResponse
- *signature:* get_grid_type(req::HTTP.Request, grid::Int64;) -> GetGridTypeResponse
- **finalize**
- *invocation:* DELETE /finalize
- *signature:* finalize(req::HTTP.Request;) -> Nothing
- **initialize**
- *invocation:* POST /initialize
- *signature:* initialize(req::HTTP.Request, bmi_initialize_request::BmiInitializeRequest;) -> Nothing
- *signature:* initialize(req::HTTP.Request, initialize_request::InitializeRequest;) -> Nothing
- **update**
- *invocation:* POST /update
- *signature:* update(req::HTTP.Request;) -> Nothing
Expand All @@ -63,7 +63,7 @@ The following server methods must be implemented:
- *signature:* set_value(req::HTTP.Request, name::String, request_body::Vector{Float64};) -> Nothing
- **set_value_at_indices**
- *invocation:* POST /set_value_at_indices/{name}
- *signature:* set_value_at_indices(req::HTTP.Request, name::String, bmi_set_value_at_indices_request::BmiSetValueAtIndicesRequest;) -> Nothing
- *signature:* set_value_at_indices(req::HTTP.Request, name::String, set_value_at_indices_request::SetValueAtIndicesRequest;) -> Nothing
- **get_current_time**
- *invocation:* GET /get_current_time
- *signature:* get_current_time(req::HTTP.Request;) -> Float64
Expand Down Expand Up @@ -123,7 +123,7 @@ The following server methods must be implemented:
- *signature:* get_var_nbytes(req::HTTP.Request, name::String;) -> Int64
- **get_var_type**
- *invocation:* GET /get_var_type/{name}
- *signature:* get_var_type(req::HTTP.Request, name::String;) -> String
- *signature:* get_var_type(req::HTTP.Request, name::String;) -> GetVarTypeResponse
- **get_var_units**
- *invocation:* GET /get_var_units/{name}
- *signature:* get_var_units(req::HTTP.Request, name::String;) -> String
Expand Down Expand Up @@ -187,10 +187,11 @@ function register(router::HTTP.Router, impl; path_prefix::String="", optional_mi
end

# export models
export BmiGetGridTypeResponse
export BmiInitializeRequest
export BmiSetValueAtIndicesRequest
export GetGridTypeResponse
export GetVarLocationResponseLocation
export GetVarTypeResponse
export InitializeRequest
export ProblemDetails
export SetValueAtIndicesRequest

end # module BmiServer
18 changes: 15 additions & 3 deletions RemoteBMI.jl/src/RemoteBMI.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@ module RemoteBMI

using HTTP

# Treat returned string as something that must be JSON serialized
# At https://github.com/JuliaComputing/OpenAPI.jl/blob/2d447986b6377a6724ae59380f087c2b270e7795/src/server.jl#L167
# string is force tod return as plain text
# Treat returned string from route implementations as thing that must be JSON serialized
# Without this, the string would be returned as plain text
#using OpenAPI
#using OpenAPI.Servers
#OpenAPI.Servers.server_response(resp::AbstractString, headers=HTTP.Headers()) = OpenAPI.Servers.server_response(OpenAPI.to_json(resp), [Pair("Content-Type", "application/json")])
# TODO find way that does not break OpenAPI.Servers.server_response as with overwrite a client request is timing out
# TODO Alternative is to return plain/text in paths that return strings

include("./BmiServer.jl")
using .BmiServer

import BasicModelInterface as BMI

# TODO move route implementations to own module

function initialize(req::HTTP.Request, bmi_initialize_request::BmiInitializeRequest)::Nothing
function initialize(req::HTTP.Request, bmi_initialize_request::InitializeRequest)::Nothing
global m
m = BMI.initialize(MyModel, bmi_initialize_request.config_file)
return nothing
Expand Down Expand Up @@ -119,6 +130,7 @@ function reserve_grid_coords(m, grid::Int64, dim_index::Int8)::Vector{Float64}
size = BMI.get_grid_node_count(m, grid)
else
error("Unsupported grid type: $mtype")
end
return zeros(Float64, size)
end

Expand All @@ -141,7 +153,7 @@ function set_value(req::HTTP.Request, name::String, request_body::Vector{Float64
BMI.set_value(m, name, request_body)
end

function set_value_at_indices(req::HTTP.Request, name::String, bmi_set_value_at_indices_request::BmiSetValueAtIndicesRequest;)::Nothing
function set_value_at_indices(req::HTTP.Request, name::String, bmi_set_value_at_indices_request::SetValueAtIndicesRequest;)::Nothing
BMI.set_value_at_indices(m, name, bmi_set_value_at_indices_request)
end

Expand Down Expand Up @@ -274,7 +286,7 @@ function get_var_units(req::HTTP.Request, name::String;)::String
return BMI.get_var_units(m, name)
end

function run(model, host, port)
function run(model, host, port, trusted_apikey)
global MyModel = model
try
router = HTTP.Router()
Expand Down
4 changes: 4 additions & 0 deletions RemoteBMI.jl/src/apis/api_GettersApi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ function get_value_validate(handler)
function get_value_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_value", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -46,6 +48,8 @@ function get_value_at_indices_validate(handler)
function get_value_at_indices_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_value_at_indices", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down
4 changes: 2 additions & 2 deletions RemoteBMI.jl/src/apis/api_IRFApi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ end
function initialize_read(handler)
function initialize_read_handler(req::HTTP.Request)
openapi_params = Dict{String,Any}()
openapi_params["BmiInitializeRequest"] = OpenAPI.Servers.to_param_type(BmiInitializeRequest, String(req.body))
openapi_params["InitializeRequest"] = OpenAPI.Servers.to_param_type(InitializeRequest, String(req.body))
req.context[:openapi_params] = openapi_params

return handler(req)
Expand All @@ -49,7 +49,7 @@ end
function initialize_invoke(impl; post_invoke=nothing)
function initialize_invoke_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]
ret = impl.initialize(req::HTTP.Request, openapi_params["BmiInitializeRequest"];)
ret = impl.initialize(req::HTTP.Request, openapi_params["InitializeRequest"];)
resp = OpenAPI.Servers.server_response(ret)
return (post_invoke === nothing) ? resp : post_invoke(req, resp)
end
Expand Down
8 changes: 6 additions & 2 deletions RemoteBMI.jl/src/apis/api_SettersApi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ function set_value_validate(handler)
function set_value_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "set_value", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand All @@ -36,7 +38,7 @@ function set_value_at_indices_read(handler)
openapi_params = Dict{String,Any}()
path_params = HTTP.getparams(req)
openapi_params["name"] = OpenAPI.Servers.to_param(String, path_params, "name", required=true, )
openapi_params["BmiSetValueAtIndicesRequest"] = OpenAPI.Servers.to_param_type(BmiSetValueAtIndicesRequest, String(req.body))
openapi_params["SetValueAtIndicesRequest"] = OpenAPI.Servers.to_param_type(SetValueAtIndicesRequest, String(req.body))
req.context[:openapi_params] = openapi_params

return handler(req)
Expand All @@ -47,14 +49,16 @@ function set_value_at_indices_validate(handler)
function set_value_at_indices_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "set_value_at_indices", :minLength, openapi_params["name"], 1)

return handler(req)
end
end

function set_value_at_indices_invoke(impl; post_invoke=nothing)
function set_value_at_indices_invoke_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]
ret = impl.set_value_at_indices(req::HTTP.Request, openapi_params["name"], openapi_params["BmiSetValueAtIndicesRequest"];)
ret = impl.set_value_at_indices(req::HTTP.Request, openapi_params["name"], openapi_params["SetValueAtIndicesRequest"];)
resp = OpenAPI.Servers.server_response(ret)
return (post_invoke === nothing) ? resp : post_invoke(req, resp)
end
Expand Down
12 changes: 12 additions & 0 deletions RemoteBMI.jl/src/apis/api_VariableInformationApi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ function get_var_grid_validate(handler)
function get_var_grid_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_grid", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -45,6 +47,8 @@ function get_var_itemsize_validate(handler)
function get_var_itemsize_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_itemsize", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -73,6 +77,8 @@ function get_var_location_validate(handler)
function get_var_location_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_location", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -101,6 +107,8 @@ function get_var_nbytes_validate(handler)
function get_var_nbytes_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_nbytes", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -129,6 +137,8 @@ function get_var_type_validate(handler)
function get_var_type_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_type", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down Expand Up @@ -157,6 +167,8 @@ function get_var_units_validate(handler)
function get_var_units_validate_handler(req::HTTP.Request)
openapi_params = req.context[:openapi_params]

OpenAPI.validate_param("name", "get_var_units", :minLength, openapi_params["name"], 1)

return handler(req)
end
end
Expand Down
7 changes: 4 additions & 3 deletions RemoteBMI.jl/src/modelincludes.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# This file was generated by the Julia OpenAPI Code Generator
# Do not modify this file directly. Modify the OpenAPI specification instead.

include("models/model_BmiGetGridTypeResponse.jl")
include("models/model_BmiInitializeRequest.jl")
include("models/model_BmiSetValueAtIndicesRequest.jl")
include("models/model_GetGridTypeResponse.jl")
include("models/model_GetVarLocationResponseLocation.jl")
include("models/model_GetVarTypeResponse.jl")
include("models/model_InitializeRequest.jl")
include("models/model_ProblemDetails.jl")
include("models/model_SetValueAtIndicesRequest.jl")
9 changes: 0 additions & 9 deletions RemoteBMI.jl/src/models/model_BmiGetGridTypeResponse.jl

This file was deleted.

30 changes: 0 additions & 30 deletions RemoteBMI.jl/src/models/model_BmiInitializeRequest.jl

This file was deleted.

34 changes: 0 additions & 34 deletions RemoteBMI.jl/src/models/model_BmiSetValueAtIndicesRequest.jl

This file was deleted.

Loading