fixeria has uploaded this change for review. (
https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41100?usp=email )
Change subject: [REST] Implement Pfcp{AssocState,Heartbeat}
......................................................................
[REST] Implement Pfcp{AssocState,Heartbeat}
Change-Id: Idc98952d46d8e224969da343dc29ef323c6ed813
Related: SYS#7066
---
M contrib/openapi.yaml
M contrib/osmo-s1gw-cli.py
M priv/openapi.json
M src/rest_server.erl
4 files changed, 278 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/erlang/osmo-s1gw refs/changes/00/41100/1
diff --git a/contrib/openapi.yaml b/contrib/openapi.yaml
index 696e7a2..df079a9 100644
--- a/contrib/openapi.yaml
+++ b/contrib/openapi.yaml
@@ -32,8 +32,61 @@
schema:
$ref: '#/components/schemas/MetricsList'
+ /pfcp/assoc:
+ get:
+ summary: Get the PFCP association state
+ operationId: PfcpAssocState
+ responses:
+ '200':
+ description: PFCP association state
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PfcpAssocState'
+ post:
+ summary: Initiate the PFCP Association Setup procedure
+ operationId: PfcpAssocSetup
+ responses:
+ '200':
+ $ref: '#/components/responses/OperationResult'
+ delete:
+ summary: Initiate the PFCP Association Release procedure
+ operationId: PfcpAssocRelease
+ responses:
+ '200':
+ $ref: '#/components/responses/OperationResult'
+
+ /pfcp/heartbeat:
+ post:
+ summary: Send a PFCP Heartbeat Request to the peer
+ operationId: PfcpHeartbeat
+ responses:
+ '200':
+ $ref: '#/components/responses/OperationResult'
+
components:
+ responses:
+ OperationResult:
+ description: Generic operation result response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/OperationResult'
+
schemas:
+ OperationResult:
+ type: object
+ required:
+ - success
+ properties:
+ success:
+ type: boolean
+ description: Indicates whether the operation was successful
+ message:
+ type: string
+ nullable: true
+ description: Human-readable explanation of the result
+
MetricsList:
type: array
items:
@@ -53,3 +106,27 @@
type: string
value:
type: integer
+
+ PfcpAssocState:
+ type: object
+ required:
+ - state
+ - laddr
+ - raddr
+ properties:
+ state:
+ type: string
+ enum: [connecting, connected]
+ description: Current association state
+ laddr:
+ type: string
+ description: Local (bind) IP address
+ raddr:
+ type: string
+ description: Remote (connect) IP address
+ lrts:
+ type: integer
+ description: Local Recovery TimeStamp
+ rrts:
+ type: integer
+ description: Remote Recovery TimeStamp
diff --git a/contrib/osmo-s1gw-cli.py b/contrib/osmo-s1gw-cli.py
index 9888ee9..7b58b37 100755
--- a/contrib/osmo-s1gw-cli.py
+++ b/contrib/osmo-s1gw-cli.py
@@ -81,11 +81,32 @@
with self.send_get_req('metrics-list', query) as f:
return json.load(f)
+ def pfcp_assoc_state(self) -> RESTResponse:
+ ''' PfcpAssocState :: Get the PFCP association state '''
+ with self.send_get_req('pfcp/assoc') as f:
+ return json.load(f)
+
+ def pfcp_assoc_setup(self) -> RESTResponse:
+ ''' PfcpAssocSetup :: Initiate the PFCP Association Setup procedure
'''
+ with self.send_post_req('pfcp/assoc') as f:
+ return json.load(f)
+
+ def pfcp_assoc_release(self) -> RESTResponse:
+ ''' PfcpAssocRelease :: Initiate the PFCP Association Release
procedure '''
+ with self.send_delete_req('pfcp/assoc') as f:
+ return json.load(f)
+
+ def pfcp_heartbeat(self) -> RESTResponse:
+ ''' PfcpHeartbeat :: Send a PFCP Heartbeat Request to the peer
'''
+ with self.send_post_req('pfcp/heartbeat') as f:
+ return json.load(f)
+
class OsmoS1GWCli(cmd2.Cmd):
DESC = 'Interactive CLI for OsmoS1GW'
CAT_METRICS = 'Metrics commands'
+ CAT_PFCP = 'PFCP related commands'
def __init__(self, argv):
super().__init__(allow_cli_args=False, include_py=True)
@@ -134,6 +155,37 @@
self.poutput(tabulate.tabulate(map(self.metrics_list_item, data),
headers='keys', tablefmt=self.tablefmt))
+ @cmd2.with_category(CAT_PFCP)
+ def do_pfcp_assoc_state(self, opts) -> None:
+ ''' Get the PFCP association state '''
+ data = self.iface.pfcp_assoc_state()
+ self.poutput('State: {state}\n'
+ 'Local address: {laddr}\n'
+ 'Remote address: {raddr}\n'
+ 'Local Recovery TimeStamp: {lrts}'
+ .format(**data))
+ if 'rrts' in data:
+ self.poutput('Remote Recovery TimeStamp: {rrts}'.format(**data))
+
+ @cmd2.with_category(CAT_PFCP)
+ def do_pfcp_assoc_setup(self, opts) -> None:
+ ''' Initiate the PFCP Association Setup procedure '''
+ raise NotImplementedError
+
+ @cmd2.with_category(CAT_PFCP)
+ def do_pfcp_assoc_release(self, opts) -> None:
+ ''' Initiate the PFCP Association Release procedure '''
+ raise NotImplementedError
+
+ @cmd2.with_category(CAT_PFCP)
+ def do_pfcp_heartbeat(self, opts) -> None:
+ ''' Send a PFCP Heartbeat Request '''
+ data = self.iface.pfcp_heartbeat()
+ if data['success']:
+ self.poutput('Heartbeat succeeded')
+ else:
+ self.perror('Heartbeat failed: {message}'.format(**data))
+
ap = argparse.ArgumentParser(prog='osmo-s1gw-cli', description=OsmoS1GWCli.DESC)
diff --git a/priv/openapi.json b/priv/openapi.json
index 7323e9a..c55c312 100644
--- a/priv/openapi.json
+++ b/priv/openapi.json
@@ -49,10 +49,86 @@
}
}
}
+ },
+ "/pfcp/assoc": {
+ "get": {
+ "summary": "Get the PFCP association state",
+ "operationId": "PfcpAssocState",
+ "responses": {
+ "200": {
+ "description": "PFCP association state",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref":
"#/components/schemas/PfcpAssocState"
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "summary": "Initiate the PFCP Association Setup
procedure",
+ "operationId": "PfcpAssocSetup",
+ "responses": {
+ "200": {
+ "$ref":
"#/components/responses/OperationResult"
+ }
+ }
+ },
+ "delete": {
+ "summary": "Initiate the PFCP Association Release
procedure",
+ "operationId": "PfcpAssocRelease",
+ "responses": {
+ "200": {
+ "$ref":
"#/components/responses/OperationResult"
+ }
+ }
+ }
+ },
+ "/pfcp/heartbeat": {
+ "post": {
+ "summary": "Send a PFCP Heartbeat Request to the
peer",
+ "operationId": "PfcpHeartbeat",
+ "responses": {
+ "200": {
+ "$ref":
"#/components/responses/OperationResult"
+ }
+ }
+ }
}
},
"components": {
+ "responses": {
+ "OperationResult": {
+ "description": "Generic operation result response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref":
"#/components/schemas/OperationResult"
+ }
+ }
+ }
+ }
+ },
"schemas": {
+ "OperationResult": {
+ "type": "object",
+ "required": [
+ "success"
+ ],
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "description": "Indicates whether the operation
was successful"
+ },
+ "message": {
+ "type": "string",
+ "nullable": true,
+ "description": "Human-readable explanation of the
result"
+ }
+ }
+ },
"MetricsList": {
"type": "array",
"items": {
@@ -81,6 +157,40 @@
"type": "integer"
}
}
+ },
+ "PfcpAssocState": {
+ "type": "object",
+ "required": [
+ "state",
+ "laddr",
+ "raddr"
+ ],
+ "properties": {
+ "state": {
+ "type": "string",
+ "enum": [
+ "connecting",
+ "connected"
+ ],
+ "description": "Current association state"
+ },
+ "laddr": {
+ "type": "string",
+ "description": "Local (bind) IP address"
+ },
+ "raddr": {
+ "type": "string",
+ "description": "Remote (connect) IP address"
+ },
+ "lrts": {
+ "type": "integer",
+ "description": "Local Recovery TimeStamp"
+ },
+ "rrts": {
+ "type": "integer",
+ "description": "Remote Recovery TimeStamp"
+ }
+ }
}
}
}
diff --git a/src/rest_server.erl b/src/rest_server.erl
index ee0a7de..d1597a9 100644
--- a/src/rest_server.erl
+++ b/src/rest_server.erl
@@ -34,7 +34,9 @@
-module(rest_server).
--export([metrics_list/1
+-export([metrics_list/1,
+ pfcp_assoc_state/1,
+ pfcp_heartbeat/1
]).
-include_lib("kernel/include/logger.hrl").
@@ -60,6 +62,28 @@
{200, [], L1}.
+%% PfcpAssocState :: Get the PFCP association state
+pfcp_assoc_state(#{}) ->
+ Info0 = pfcp_peer:fetch_info(),
+ Info1 = maps:update_with(laddr, fun inet:ntoa/1, Info0),
+ Info2 = maps:update_with(raddr, fun inet:ntoa/1, Info1),
+ {200, [], rsp_map(Info2)}.
+
+%% TODO: PfcpAssocSetup :: Initiate the PFCP Association Setup procedure
+%% TODO: PfcpAssocRelease :: Initiate the PFCP Association Release procedure
+
+
+%% PfcpHeartbeat :: Send a PFCP Heartbeat Request to the peer
+pfcp_heartbeat(#{}) ->
+ case pfcp_peer:heartbeat_req() of
+ ok ->
+ {200, [], rsp_map(#{success => true})};
+ {error, Error} ->
+ {200, [], rsp_map(#{success => false,
+ message => Error})}
+ end.
+
+
%% ------------------------------------------------------------------
%% private API
%% ------------------------------------------------------------------
@@ -107,4 +131,18 @@
thing_to_list(X) when is_list(X) -> X.
+%% Convert the given response map to a format acceptable by the erf
+-spec rsp_map(map()) -> map().
+rsp_map(M) ->
+ Fun = fun(K, V) -> {bval(K), bval(V)} end,
+ maps:from_list([Fun(K, V) || {K, V} <- maps:to_list(M)]).
+
+
+bval(V) when is_boolean(V) -> V;
+bval(V) when is_atom(V) -> atom_to_binary(V);
+bval(V) when is_list(V) -> list_to_binary(V);
+bval(V) when is_map(V) -> rsp_map(V);
+bval(V) -> V.
+
+
%% vim:set ts=4 sw=4 et:
--
To view, visit
https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41100?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: erlang/osmo-s1gw
Gerrit-Branch: master
Gerrit-Change-Id: Idc98952d46d8e224969da343dc29ef323c6ed813
Gerrit-Change-Number: 41100
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>