Release of Routing Manager v0.3.0 54/454/5
authorkalnagy <kalman.nagy@nokia.com>
Tue, 2 Jul 2019 13:15:49 +0000 (15:15 +0200)
committerkalnagy <kalman.nagy@nokia.com>
Tue, 9 Jul 2019 15:02:23 +0000 (17:02 +0200)
Change-Id: Ic00bfdcce265726094ba133c39fb72ba2e5208a7
Signed-off-by: kalnagy <kalman.nagy@nokia.com>
50 files changed:
.gitignore
.gitreview
Dockerfile
README.md
RELNOTES
api/routing_manager.yaml
build.sh [deleted file]
cmd/rtmgr.go
container-tag.yaml
glide.lock [new file with mode: 0644]
glide.yaml [moved from pkg/glide.yaml with 73% similarity]
manifests/rtmgr/rtmgr-cfg.yaml [new file with mode: 0644]
manifests/rtmgr/rtmgr-dep.yaml
manifests/rtmgr/rtmgr-svc.yaml
pkg/glide.lock [deleted file]
pkg/nbi/httpgetter.go
pkg/nbi/httpgetter_test.go [new file with mode: 0644]
pkg/nbi/httprestful.go [new file with mode: 0644]
pkg/nbi/httprestful_test.go [new file with mode: 0644]
pkg/nbi/nbi.go
pkg/nbi/nbi_test.go [new file with mode: 0644]
pkg/nbi/types.go
pkg/rpe/rmr.go
pkg/rpe/rmr_test.go [new file with mode: 0644]
pkg/rpe/rpe.go
pkg/rpe/types.go
pkg/rtmgr/rtmgr.go
pkg/rtmgr/rtmgr_test.go [new file with mode: 0644]
pkg/rtmgr/types.go
pkg/sbi/nngpub.go
pkg/sbi/nngpub_test.go [new file with mode: 0644]
pkg/sbi/nngpush.go
pkg/sbi/nngpush_test.go [new file with mode: 0644]
pkg/sbi/sbi.go
pkg/sbi/sbi_test.go [new file with mode: 0644]
pkg/sbi/types.go
pkg/sdl/file.go
pkg/sdl/sdl.go
pkg/sdl/sdl_test.go [new file with mode: 0644]
pkg/sdl/types.go
pkg/stub/mangos.go [new file with mode: 0644]
pkg/stub/stub.go [new file with mode: 0644]
run_rtmgr.sh [moved from build/container/run_rtmgr.sh with 86% similarity, mode: 0644]
test/data/platform_routes.json [new file with mode: 0644]
test/data/xapps.json [new file with mode: 0644]
test/docker/xmgr.build/Dockerfile
test/docker/xmgr.build/middleware.js [new file with mode: 0644]
test/kubernetes/xapp-tx/xapp-tx.yaml
test/kubernetes/xmgr/xmgr-cfg.yaml
test/kubernetes/xmgr/xmgr-dep.yaml

index e69de29..66d38c8 100644 (file)
@@ -0,0 +1,3 @@
+vendor
+bin
+pkg/sdl/ut.rt
index a7f2fae..fbe7867 100644 (file)
@@ -3,3 +3,4 @@ host=gerrit.o-ran-sc.org
 port=29418
 project=ric-plt/rtmgr
 defaultbranch=master
 port=29418
 project=ric-plt/rtmgr
 defaultbranch=master
+defaultremote=origin
index 10cdd1c..6bbbb5c 100644 (file)
 # a Docker tag from the string in file container-tag.yaml
 
 FROM golang:1.12 as rtmgrbuild
 # a Docker tag from the string in file container-tag.yaml
 
 FROM golang:1.12 as rtmgrbuild
-ENV GOPATH /opt
+ENV GOPATH /go
 RUN apt-get update \
 RUN apt-get update \
-    && apt-get install golang-glide
-COPY . /opt
-RUN mkdir -p $GOPATH/bin \
-    && ln -s -f  $GOPATH/pkg $GOPATH/src \
-    && cd $GOPATH/src \
-    && glide install --strip-vendor \
-    && cd $GOPATH/cmd \
-    && go build rtmgr.go \
-    && mv $GOPATH/cmd/rtmgr $GOPATH/bin
+    && apt-get install -y golang-glide git wget
 
 
+RUN cd /go/bin \
+    && wget --quiet https://github.com/go-swagger/go-swagger/releases/download/v0.19.0/swagger_linux_amd64 \
+    && mv swagger_linux_amd64 swagger \
+    && chmod +x swagger
+
+COPY . /go/src/routing-manager
+
+WORKDIR /go/src/routing-manager
+
+RUN git clone "https://gerrit.o-ran-sc.org/r/ric-plt/appmgr" \
+    && cp appmgr/api/appmgr_rest_api.json api/ \
+    && rm -rf appmgr
+
+RUN swagger generate server -f api/routing_manager.yaml -t pkg/ --exclude-main -r LICENSE
+RUN swagger generate client -f api/appmgr_rest_api.json -t pkg/ -m appmgr_model -c appmgr_client -r LICENSE
+
+RUN glide install --strip-vendor
+
+RUN go build cmd/rtmgr.go \
+    && cp rtmgr /go/bin/rtmgr \
+    && cp run_rtmgr.sh /run_rtmgr.sh
+
+# UT intermediate container
+FROM rtmgrbuild as rtmgrut
+RUN go test ./pkg/sbi ./pkg/rpe ./pkg/nbi ./pkg/sdl -cover -race
+
+# Final, executable container
 FROM ubuntu:16.04
 FROM ubuntu:16.04
-COPY --from=rtmgrbuild /opt/bin/rtmgr /
-RUN mkdir /db && touch /db/rt.json
-CMD /rtmgr
+COPY --from=rtmgrbuild /go/bin/rtmgr /
+COPY --from=rtmgrbuild /run_rtmgr.sh /
+RUN mkdir /db && touch /db/rt.json && chmod 777 /db/rt.json
+CMD /run_rtmgr.sh
+
index 2cc2000..3f132d2 100644 (file)
--- a/README.md
+++ b/README.md
 ## Introduction
 __Routing Manager__ is a basic platform service of RIC. It is responsible for distributing routing policies among the other platform components and xApps.
 
 ## Introduction
 __Routing Manager__ is a basic platform service of RIC. It is responsible for distributing routing policies among the other platform components and xApps.
 
-The implemented logic periodically queries the xApp Manager component for xApps' list. Stores the data then processes it to create routing policies and distributes them to all xApps.
+The routing manager has two ways to get the xapp details from xapp manager - httpGetter or httpRESTful.
+In case of httpGetter, the implemented logic periodically queries the xApp Manager component for xApps' list.
+Where in httpRESTful, starts a http server and creates a webhook subscription in xapp manager to update about changes in xapps and waits changed data to arrive on the REST http server.
+Either ways, the xapp data received is stored and then processed to create routing policies and distributes them to all xApps.
+
 The architecture consists of the following five well defined functions:
 * NorthBound Interface (__NBI__): Maintains the communication channels towards RIC manager components 
 * Routing Policy Engine (__RPE__): Provides the logic to calculate routing policies
 * Shared Data Layer (__SDL__): Provides access to different kind persistent data stores
 * SouthBound Interface (__SBI__): Maintains the communication channels towards RIC tenants and control components
 The architecture consists of the following five well defined functions:
 * NorthBound Interface (__NBI__): Maintains the communication channels towards RIC manager components 
 * Routing Policy Engine (__RPE__): Provides the logic to calculate routing policies
 * Shared Data Layer (__SDL__): Provides access to different kind persistent data stores
 * SouthBound Interface (__SBI__): Maintains the communication channels towards RIC tenants and control components
-* Control Logic (__RTMGR__): Controls the operatin of above functions
+* Control Logic (__RTMGR__): Controls the operation of above functions
 
 Current implementation provides support for the followings:
 * NBI:
   * __httpGet__: simple HTTP GET interface. Expects an URL where it gets the xApps' list in JSON format
 
 Current implementation provides support for the followings:
 * NBI:
   * __httpGet__: simple HTTP GET interface. Expects an URL where it gets the xApps' list in JSON format
-  * (WIP) __httRESTful__: provides REST API endpoints towards RIC manager components 
+  * __httRESTful__: provides REST API endpoints towards RIC manager components. Expects REST port and url where the HTTP service will be started to listen on.
 * RPE:
   * __rmr__: creates routing policies formatted for RIC RMR
 * SDL:
 * RPE:
   * __rmr__: creates routing policies formatted for RIC RMR
 * SDL:
@@ -35,30 +39,49 @@ Current implementation provides support for the followings:
   * (backlog) __sdl__: Shared Data Library to Redis database
 * SBI:
   * __nngpub__: distributes RPE created policies via NNG Pub channel
   * (backlog) __sdl__: Shared Data Library to Redis database
 * SBI:
   * __nngpub__: distributes RPE created policies via NNG Pub channel
-  * (WIP) __nngpipe__: distributes RPE created policies via NNG Pipeline channel
+  * __nngpipe__: distributes RPE created policies via NNG Pipeline channel
 
 ## Release notes
 Check the separated `RELNOTES` file.
 
 ## Prerequisites
 
 ## Release notes
 Check the separated `RELNOTES` file.
 
 ## Prerequisites
-* Healthy kubernetes cluster
-* Access to the common docker registry
+* Healthy kubernetes cluster (for Kubernetes testing)
+* Access to the common docker registry (alternatively, you can set up your own private registry for testing: https://docs.docker.com/registry/deploying/)
+* In case of non-Docker build: golang 11.1 at least, go-swagger (https://github.com/go-swagger/go-swagger, v0.19.0), glide (https://github.com/Masterminds/glide), XApp Manager spec file (available in ORAN: https://gerrit.o-ran-sc.org/r/admin/repos/ric-plt/appmgr under api folder)
 
 ## Project folder structure
 
 ## Project folder structure
-* /api: contains Swagger source files
-* /build: contains build tools (scripts, Dockerfiles, etc.)
+* /api: contains Swagger spec files
 * /manifest: contains deployment files (Kubernetes manifests, Helm chart)
 * /cmd: contains go project's main file
 * /pkg: contains go project's internal packages
 * /test: contains CI/CD testing files (scripts, mocks, manifests)
 * /manifest: contains deployment files (Kubernetes manifests, Helm chart)
 * /cmd: contains go project's main file
 * /pkg: contains go project's internal packages
 * /test: contains CI/CD testing files (scripts, mocks, manifests)
+* Dockerfile: contains main docker file
+* container-tag.yaml: contains CI specific container tag information
+* run_rtmgr.sh: shell script to run rtmgr (requires environment variables to be set)
 
 ## Installation guide
 
 ### Compiling code
 
 ## Installation guide
 
 ### Compiling code
-Enter the project root and execute `./build.sh` script.
-The build script has two main phases. First is the code compilation, where it creates a temporary container for downloading all dependencies then compiles the code. In the second phase it builds the production ready container and taggs it to `rtmgr:builder`
-
-**NOTE:** The script puts a copy of the binary into the `./bin` folder for further use cases
+#### Docker compile
+The Dockerfile located in the project root folder does the following three things:
+- As a first step, it creates a build container, fetches XApp Manager's spec file, generates rest api code from swagger spec and builds rtmgr.
+- As a second step, it executes UTs on rtmgr source code.
+- As a third step, it creates the final container from rtmgr binary (Ubuntu based).
+For a docker build execute `docker build --tag=rtmgr-build:test .` in the project root directory (feel free to replace the name:tag with your own)
+
+#### Compiling without docker
+Compiling without Docker involves some manual steps before compiling directly with "go build".
+The XApp manager's spec file must be fetched, then api generated with swagger. (these steps are included in the Dockerfile).
+After the code is generated, glide can install the dependencies of rtmgr.
+Make sure you set your GOPATH variable correctly (example: $HOME/go/src/routing-manager)
+Code generation and building example (from project root folder):
+```bash
+git clone "https://gerrit.o-ran-sc.org/r/ric-plt/appmgr" && cp appmgr/api/appmgr_rest_api.yaml api/
+swagger generate server -f api/routing_manager.yaml -t pkg/ --exclude-main -r LICENSE
+swagger generate client -f api/appmgr_rest_api.yaml -t pkg/ -m appmgr_model -c appmgr_client -r LICENSE
+glide install --strip-vendor
+go build cmd/rtmgr.go
+```
 
 ### Installing Routing Manager
 #### Preparing environment
 
 ### Installing Routing Manager
 #### Preparing environment
@@ -66,20 +89,37 @@ Tag the `rtmgr` container according to the project release and push it to a regi
 Edit the container image section of `rtmgr-dep.yaml` file according to the `rtmgr` image tag.
 
 #### Deploying Routing Manager 
 Edit the container image section of `rtmgr-dep.yaml` file according to the `rtmgr` image tag.
 
 #### Deploying Routing Manager 
-Issue the `kubectl create -f {manifest.yaml}` command in the following order
+Issue the `kubectl create -f {manifest.yaml}` command in the following order:
   1. `manifests/namespace.yaml`: creates the `example` namespace for routing-manager resources
   1. `manifests/namespace.yaml`: creates the `example` namespace for routing-manager resources
-  2. `manifests/rtmgr/rtmgr-dep.yaml`: instantiates the `rtmgr` deployment in the `example` namespace
-  3. `manifests/rtmgr/rtmgr-svc.yaml`: creates the `rtmgr` service in `example` namespace
+  2. `manifests/rtmgr/rtmgr-cfg.yaml`: creates default routes config file for routing-manager
+  3. `manifests/rtmgr/rtmgr-dep.yaml`: instantiates the `rtmgr` deployment in the `example` namespace
+  4. `manifests/rtmgr/rtmgr-svc.yaml`: creates the `rtmgr` service in `example` namespace
+
+**NOTE:** The above manifest files will deploy routing manager with NBI as httpRESTful which would not succeed unless there is an xapp manager running at the defined xm-url. The solution is either to deploy a real XAPP manager before deploying routing-manager or start the mock xmgr as mentioned in [Testing](#testing-and-troubleshoting).
 
 ### Testing and Troubleshoting
 
 ### Testing and Troubleshoting
+### Testing with Kubernetes
 Routing Manager's behaviour can be tested using the mocked xApp Manager, traffic generator xApp and receiver xApp.
 
 Routing Manager's behaviour can be tested using the mocked xApp Manager, traffic generator xApp and receiver xApp.
 
-  1. Checkout and compile both xApp receiver and xApp Tx generator of RIC admission control project
+  1. Checkout and compile both xApp receiver and xApp Tx generator of RIC admission control project: `https://gerrit.o-ran-sc.org/r/admin/repos/ric-app/admin`
   2. Copy the `adm-ctrl-xapp` binary to `./test/docker/xapp.build` folder furthermore copy all RMR related dinamycally linked library under `./test/docker/xapp.build/usr` folder. Issue `docker build ./test/docker/xapp.build` command. Tag the recently created docker image and push it to the common registry.
   3. Copy the `test-tx` binary to `./test/docker/xapp-tx.build` folder furthermore copy all RMR related dinamycally linked library under `./test/docker/xapp.build/usr` folder. Issue `docker build ./test/docker/xapp-tx.build` command.  Tag the recently created docker image and push it to the common registry.
   4. Enter the `./test/docker/xmgr.build` folder and issue `docker build .`.  Tag the recently created docker image and push it to the common registry.
   5. Modify the docker image version in each kuberbetes manifest files under `./test/kubernetes/` folder accordingly then issue the `kubectl create -f {manifest.yaml}` on each file.
   6. [Compile](#compiling-code) and [Install routing manager](#installing-routing-manager)
   2. Copy the `adm-ctrl-xapp` binary to `./test/docker/xapp.build` folder furthermore copy all RMR related dinamycally linked library under `./test/docker/xapp.build/usr` folder. Issue `docker build ./test/docker/xapp.build` command. Tag the recently created docker image and push it to the common registry.
   3. Copy the `test-tx` binary to `./test/docker/xapp-tx.build` folder furthermore copy all RMR related dinamycally linked library under `./test/docker/xapp.build/usr` folder. Issue `docker build ./test/docker/xapp-tx.build` command.  Tag the recently created docker image and push it to the common registry.
   4. Enter the `./test/docker/xmgr.build` folder and issue `docker build .`.  Tag the recently created docker image and push it to the common registry.
   5. Modify the docker image version in each kuberbetes manifest files under `./test/kubernetes/` folder accordingly then issue the `kubectl create -f {manifest.yaml}` on each file.
   6. [Compile](#compiling-code) and [Install routing manager](#installing-routing-manager)
+  7. Once the routing manager is started, it retrievs the initial xapp list from `xmgr` via HTTPGet additonaly it starts to listen on http://rtmgr:8888/v1/handles/xapp-handle endpoint and ready to receive xapp list updates.
+  8. Edit the provided `test/data/xapp.json` file accordingly and issue the following curl command to update `rtmgr's` xapp list.
+     ``` curl --header "Content-Type: application/json" --request POST --data '@./test/data/xapps.json' http://10.244.2.104:8888/v1/handles/xapp-handle ```
+
+### Executing unit tests
+For running unit tests, execute the following command:
+  `go test ./pkg/nbi` (or any package - feel free to add your own parameters)
+If you wish to execute the full UT set with coverage:
+```bash
+  mkdir -p unit-test
+  go test ./pkg/sbi ./pkg/rpe ./pkg/nbi ./pkg/sdl -cover -race -coverprofile=$PWD/unit-test/c.out
+  go tool cover -html=$PWD/unit-test/c.out -o $PWD/unit-test/coverage.htm
+```
 
 #### Command line arguments
 Routing manager binary can be called with `-h` flag when it displays the available command line arguments and it's default value.
 
 #### Command line arguments
 Routing manager binary can be called with `-h` flag when it displays the available command line arguments and it's default value.
@@ -88,12 +128,16 @@ Example:
 
 ```bash
 Usage of ./rtmgr:
 
 ```bash
 Usage of ./rtmgr:
+  -configfile string
+        Routing manager's configuration file path (default "/etc/rtmgrcfg.json")
   -filename string
         Absolute path of file where the route information to be stored (default "/db/rt.json")
   -loglevel string
         INFO | WARN | ERROR | DEBUG (default "INFO")
   -nbi string
   -filename string
         Absolute path of file where the route information to be stored (default "/db/rt.json")
   -loglevel string
         INFO | WARN | ERROR | DEBUG (default "INFO")
   -nbi string
-        Northbound interface module to be used. Valid values are: 'httpGetter' (default "httpGetter")
+        Northbound interface module to be used. Valid values are: 'httpGetter | httpRESTful' (default "httpGetter")
+  -nbi-if string
+        Base HTTP URL where routing manager will be listening on (default "http://localhost:8888")
   -rpe string
         Route Policy Engine to be used. Valid values are: 'rmrpush | rmrpub' (default "rmrpush")
   -sbi string
   -rpe string
         Route Policy Engine to be used. Valid values are: 'rmrpush | rmrpub' (default "rmrpush")
   -sbi string
@@ -104,15 +148,15 @@ Usage of ./rtmgr:
         Datastore enginge to be used. Valid values are: 'file' (default "file")
   -xm-url string
         HTTP URL where xApp Manager exposes the entire xApp List (default "http://localhost:3000/xapps")
         Datastore enginge to be used. Valid values are: 'file' (default "file")
   -xm-url string
         HTTP URL where xApp Manager exposes the entire xApp List (default "http://localhost:3000/xapps")
+
 ```
 
 ```
 
-For troubleshooting purpose the default logging level can be increased to `DEBUG`.
+For troubleshooting purpose the default logging level can be increased to `DEBUG`. (by hand launch it's set to INFO, kubernetes manifest has DEBUG set by default).
 
 ## Upcoming changes
 
 ## Upcoming changes
-[] Add RESTful NBI based on swagger api definition
-
 [] Add unit tests
 
 [] Add unit tests
 
+
 ## License
 This project is licensed under the Apache License, Version 2.0 - see the [LICENSE](LICENSE)
 
 ## License
 This project is licensed under the Apache License, Version 2.0 - see the [LICENSE](LICENSE)
 
index 7d797df..f6b4e0e 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -1,3 +1,17 @@
+### v0.3.0
+* Introduced platform-specific routes: basic components (e2term, ueman, subman, e2man) are stored in a json file (example in manifests/rtmgr/rtmgr-cfg.yaml)
+* Introduced subscription add functionality: /ric/v1/xapp-subscriptions endpoint is active, on a POST method it generates endpoint specific mse routing table entries
+
+### v0.2.0
+* Introduced http rest functionality
+* A way to get intial xapp data from xapp manager while booting the routing manager
+* A way to create a sinple webhook registration in the xapp-manager to listen on updates abpout changes in xapps
+
+### v0.1.1
+* Changes in swagger API definition
+* UTs for SBI, SDL and RPE modules
+* New message types according to RMR
+
 ### v0.1.0
 * Introduces NNGPush SBI module
 * Bugfixes in argument handling
 ### v0.1.0
 * Introduces NNGPush SBI module
 * Bugfixes in argument handling
@@ -17,4 +31,4 @@
 ### v0.0.1
 * Initial version of Routing Manager for CI/CD pipeline 
 * Dummy solution: still has no real routing capability
 ### v0.0.1
 * Initial version of Routing Manager for CI/CD pipeline 
 * Dummy solution: still has no real routing capability
-* Container is based on the _**tx**_ version of [admin xApp] which already implements [RMR library]
\ No newline at end of file
+* Container is based on the _**tx**_ version of [admin xApp] which already implements [RMR library]
index 11f09a3..8333d8b 100644 (file)
@@ -24,7 +24,7 @@ swagger: "2.0"
 info:
   title: Routing Manager
   description: "This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API."
 info:
   title: Routing Manager
   description: "This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API."
-  version: "0.2.2"
+  version: "0.3.0"
   license:
     name: "Apache 2.0"
     url: "http://www.apache.org/licenses/LICENSE-2.0.html"
   license:
     name: "Apache 2.0"
     url: "http://www.apache.org/licenses/LICENSE-2.0.html"
@@ -36,12 +36,10 @@ tags:
 #  externalDocs:
 #    description: "Find out more"
 #    url: "http://127.0.0.1"
 #  externalDocs:
 #    description: "Find out more"
 #    url: "http://127.0.0.1"
-- name: "route"
-  description: "Available routes"
 - name: "health"
   description: "Health of the system"
 schemes:
 - name: "health"
   description: "Health of the system"
 schemes:
-- "https"
+#- "https"
 - "http"
 paths:
   /health:
 - "http"
 paths:
   /health:
@@ -103,13 +101,13 @@ paths:
           description: "Invalid data"
         201:
           description: "Callback received"
           description: "Invalid data"
         201:
           description: "Callback received"
-  /routes:
+  /handles/xapp-subscription-handle:
     post:
       tags:
     post:
       tags:
-      - "route"
-      summary: "Add new route"
-      description: "By performing a POST method on the routes resource, the API caller is able to create a new route."
-      operationId: "add_route"
+      - "handle"
+      summary: "API for updating about new xapp subscription"
+      description: "By performing a POST method on the xapp-subscription-handle resource, the API caller is able to update the Routing manager about the creation of new subscription by an Xapp instance."
+      operationId: "provide_xapp_subscription_handle"
       consumes:
       - "application/json"
 #      - "application/yaml"
       consumes:
       - "application/json"
 #      - "application/yaml"
@@ -118,138 +116,16 @@ paths:
 #      - "application/yaml"
       parameters:
       - in: "body"
 #      - "application/yaml"
       parameters:
       - in: "body"
-        name: "route"
-        description: "Route object that needs to be created"
+        name: "xapp-subscription-data"
+        description: "xApp related subscription data"
         required: true
         schema:
         required: true
         schema:
-          $ref: "#/definitions/route"
+          $ref: "#/definitions/xapp-subscription-data"
       responses:
         400:
       responses:
         400:
-          description: "Invalid route"
+          description: "Invalid data"
         201:
         201:
-          description: "Route created"
-    put:
-      tags:
-      - "route"
-      summary: "Update an existing route"
-      description: "By performing a PUT method on the routes resource, the API caller is able to update an already existing route."
-      operationId: "update_route"
-      consumes:
-      - "application/json"
-#      - "application/yaml"
-      produces:
-      - "application/json"
-#      - "application/yaml"
-      parameters:
-      - in: "body"
-        name: "route"
-        description: "Route object that needs to be updated or created"
-        required: true
-        schema:
-          $ref: "#/definitions/route"
-      responses:
-        400:
-          description: "Invalid route ID supplied"
-        404:
-          description: "Route not found"
-        204:
-          description: "Route updated"
-    get:
-      tags:
-      - "route"
-      summary: "Retrieve the list of routes"
-      description: "By performing a GET method on the routes resource, the API caller is able to retrieve all routes"
-      operationId: "get_routes"
-      consumes:
-      - "application/json"
-#      - "application/yaml"
-      produces:
-      - "application/json"
-#      - "application/yaml"
-      responses:
-        200:
-          description: "All the routes"
-          schema:
-            $ref: "#/definitions/routes"
-
-  /routes/{route-id}:
-    get:
-      tags:
-      - "route"
-      summary: "Find route by ID"
-      description: "Returns a single route"
-      operationId: "get_route_by_id"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "route-id"
-        in: "path"
-        description: "ID of route to return"
-        required: true
-        type: "integer"
-        format: "int64"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/route"
-        400:
-          description: "Invalid route ID supplied"
-        404:
-          description: "Route not found"
-    put:
-      tags:
-      - "route"
-      summary: "Updates a route by explicitly referencing it by route-id"
-      description: "By performing a PUT method on a specific route referenced by the route-id the API caller is able to update that specific route"
-      operationId: "update-route-by-id"
-      consumes:
-      - "application/json"
-#      - "application/yaml"
-      produces:
-      - "application/json"
-#      - "application/yaml"
-      parameters:
-      - name: "route-id"
-        in: "path"
-        description: "ID of route that needs to be updated"
-        required: true
-        type: "integer"
-        format: "int64"
-      - name: "route"
-        in: "body"
-        description: "The updated route instance"
-        required: false
-        schema:
-          $ref: "#/definitions/route"
-      responses:
-        400:
-          description: "Invalid route ID supplied"
-        204:
-          description: "Route updated"
-    delete:
-      tags:
-      - "route"
-      summary: "Deletes a route"
-      description: "By performing a DELETE method on a specific route referenced by the route-id, the API caller is able to delete that specific route"
-      operationId: "delete_route_by_id"
-      produces:
-      - "application/json"
-#      - "application/yaml"
-      parameters:
-      - name: "route-id"
-        in: "path"
-        description: "ID of the route that needs to be deleted"
-        required: true
-        type: "integer"
-        format: "int64"
-      responses:
-        400:
-          description: "Invalid route ID supplied"
-        404:
-          description: "Route not found"
-        204:
-          description: "Route deleted"
+          description: "Xapp Subscription data received"
 definitions:
   health-status:
     type: "object"
 definitions:
   health-status:
     type: "object"
@@ -259,59 +135,38 @@ definitions:
         enum:
         - healthy
         - unhealthy
         enum:
         - healthy
         - unhealthy
-  routes:
-    type: "array"
-    items:
-        $ref: "#/definitions/route"
-  route:
+  xapp-callback-data:
     type: "object"
     type: "object"
-    required:
-    - "id" # not so sure about that
     properties:
       id:
         type: "integer"
         format: "int64"
     properties:
       id:
         type: "integer"
         format: "int64"
-      senders:
-        type: "array"
-        items:
-          "$ref": "#/definitions/xapp-instance"
-      message-type:
+      event:
+        type: "string"
+      data-version:
         type: "integer"
         format: "int64"
         type: "integer"
         format: "int64"
-      receiver-groups:
-        type: "array"
-        items:
-          "$ref": "#/definitions/xapp-group"
-  xapp-instance:
+      data:
+        type: "string" #This should be a JSON object, array of xapps
+  xapp-subscription-data:
     type: "object"
     required:
     type: "object"
     required:
-    - "address"
-    - "port"
+      - "address"
+      - "port"
+      - "subscription_id"
     properties:
       address:
     properties:
       address:
-        type: "string" # I know...
-      port:
+        type: "string" #This is the xapp instance hostname or ip address
+      port: #xapp instance port address
         type: "integer"
         type: "integer"
-        format: "int32"
+        format: "uint16"
         minimum: 0
         maximum: 65535
         minimum: 0
         maximum: 65535
-  xapp-group:
-    type: "array"
-    items:
-      "$ref": "#/definitions/xapp-instance"
-  xapp-callback-data:
-    type: "object"
-    properties:
-      id:
+      subscription_id: #subscription sequence number
         type: "integer"
         type: "integer"
-        format: "int64"
-      event:
-        type: "string"
-      data-version:
-        type: "integer"
-        format: "int64"
-      data:
-        type: "string" #This should be a JSON object, array of xapps
+        format: "int16" 
+
 externalDocs:
   description: "Routing Manager"
   url: "http://placeholder"
 externalDocs:
   description: "Routing Manager"
   url: "http://placeholder"
+
diff --git a/build.sh b/build.sh
deleted file mode 100755 (executable)
index e8482e9..0000000
--- a/build.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh -e
-#
-#==================================================================================
-#   Copyright (c) 2019 AT&T Intellectual Property.
-#   Copyright (c) 2019 Nokia
-#
-#   Licensed under the Apache License, Version 2.0 (the "License");
-#   you may not use this file except in compliance with the License.
-#   You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-#   Unless required by applicable law or agreed to in writing, software
-#   distributed under the License is distributed on an "AS IS" BASIS,
-#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#   See the License for the specific language governing permissions and
-#   limitations under the License.
-#==================================================================================
-#
-#
-#      Mnemonic:       build.sh
-#      Abstract:       Compiles the rtmgr source and builds the docker container
-#      Date:           12 March 2019
-#
-
-echo 'Creating compiler container'
-docker build --no-cache --tag=rtmgr_compiler:0.1 build/binary/
-
-echo 'Running rtmgr compiler'
-docker run --rm --name=rtmgr_compiler -v ${PWD}:/opt/ rtmgr_compiler:0.1
-
-echo 'Cleaning up compiler container'
-docker rmi -f rtmgr_compiler:0.1
-
-echo 'rtmgr binary successfully built!'
-
-echo 'Creating rtmgr container'
-cp ${PWD}/bin/* ${PWD}/build/container/
-docker build --no-cache --tag=rtmgr:builder build/container/
index 093da71..f2b3903 100644 (file)
@@ -28,12 +28,14 @@ package main
 
 import (
        "flag"
 
 import (
        "flag"
-       "nbi"
        "os"
        "os"
-       "rpe"
-       "rtmgr"
-       "sbi"
-       "sdl"
+       "os/signal"
+       "routing-manager/pkg/nbi"
+       "routing-manager/pkg/rpe"
+       "routing-manager/pkg/rtmgr"
+       "routing-manager/pkg/sbi"
+       "routing-manager/pkg/sdl"
+       "syscall"
        "time"
 )
 
        "time"
 )
 
@@ -45,25 +47,27 @@ var (
 )
 
 func parseArgs() {
 )
 
 func parseArgs() {
-       // TODO: arguments should be validated (filename; xm-url; sbi-if)
+       // TODO: arguments should be validated (filename; xm-url; sbi-if; rest-url; rest-port)
        args = make(map[string]*string)
        args = make(map[string]*string)
-       args["nbi"] = flag.String("nbi", "httpGetter", "Northbound interface module to be used. Valid values are: 'httpGetter'")
+       args["configfile"] = flag.String("configfile", "/etc/rtmgrcfg.json", "Routing manager's configuration file path")
+       args["nbi"] = flag.String("nbi", "httpGetter", "Northbound interface module to be used. Valid values are: 'httpGetter | httpRESTful'")
        args["sbi"] = flag.String("sbi", "nngpush", "Southbound interface module to be used. Valid values are: 'nngpush | nngpub'")
        args["rpe"] = flag.String("rpe", "rmrpush", "Route Policy Engine to be used. Valid values are: 'rmrpush | rmrpub'")
        args["sdl"] = flag.String("sdl", "file", "Datastore enginge to be used. Valid values are: 'file'")
        args["xm-url"] = flag.String("xm-url", "http://localhost:3000/xapps", "HTTP URL where xApp Manager exposes the entire xApp List")
        args["sbi"] = flag.String("sbi", "nngpush", "Southbound interface module to be used. Valid values are: 'nngpush | nngpub'")
        args["rpe"] = flag.String("rpe", "rmrpush", "Route Policy Engine to be used. Valid values are: 'rmrpush | rmrpub'")
        args["sdl"] = flag.String("sdl", "file", "Datastore enginge to be used. Valid values are: 'file'")
        args["xm-url"] = flag.String("xm-url", "http://localhost:3000/xapps", "HTTP URL where xApp Manager exposes the entire xApp List")
+       args["nbi-if"] = flag.String("nbi-if", "http://localhost:8888", "Base HTTP URL where routing manager will be listening on")
        args["sbi-if"] = flag.String("sbi-if", "0.0.0.0", "IPv4 address of interface where Southbound socket to be opened")
        args["filename"] = flag.String("filename", "/db/rt.json", "Absolute path of file where the route information to be stored")
        args["loglevel"] = flag.String("loglevel", "INFO", "INFO | WARN | ERROR | DEBUG")
        flag.Parse()
 }
 
        args["sbi-if"] = flag.String("sbi-if", "0.0.0.0", "IPv4 address of interface where Southbound socket to be opened")
        args["filename"] = flag.String("filename", "/db/rt.json", "Absolute path of file where the route information to be stored")
        args["loglevel"] = flag.String("loglevel", "INFO", "INFO | WARN | ERROR | DEBUG")
        flag.Parse()
 }
 
-func initRtmgr() (*nbi.NbiEngineConfig, *sbi.SbiEngineConfig, *sdl.SdlEngineConfig, *rpe.RpeEngineConfig, error) {
+func initRtmgr() (nbi.NbiEngine, sbi.SbiEngine, sdl.SdlEngine, rpe.RpeEngine, error) {
        var err error
        var err error
-       var nbii *nbi.NbiEngineConfig
-       var sbii *sbi.SbiEngineConfig
-       var sdli *sdl.SdlEngineConfig
-       var rpei *rpe.RpeEngineConfig
+       var nbii nbi.NbiEngine
+       var sbii sbi.SbiEngine
+       var sdli sdl.SdlEngine
+       var rpei rpe.RpeEngine
        if nbii, err = nbi.GetNbi(*args["nbi"]); err == nil && nbii != nil {
                if sbii, err = sbi.GetSbi(*args["sbi"]); err == nil && sbii != nil {
                        if sdli, err = sdl.GetSdl(*args["sdl"]); err == nil && sdli != nil {
        if nbii, err = nbi.GetNbi(*args["nbi"]); err == nil && nbii != nil {
                if sbii, err = sbi.GetSbi(*args["sbi"]); err == nil && sbii != nil {
                        if sdli, err = sdl.GetSdl(*args["sdl"]); err == nil && sdli != nil {
@@ -76,45 +80,82 @@ func initRtmgr() (*nbi.NbiEngineConfig, *sbi.SbiEngineConfig, *sdl.SdlEngineConf
        return nil, nil, nil, nil, err
 }
 
        return nil, nil, nil, nil, err
 }
 
-func serve(nbii *nbi.NbiEngineConfig, sbii *sbi.SbiEngineConfig, sdli *sdl.SdlEngineConfig, rpei *rpe.RpeEngineConfig) {
-       err := sbii.OpenSocket(*args["sbi-if"])
+func serveSBI(triggerSBI <-chan bool, sbiEngine sbi.SbiEngine, sdlEngine sdl.SdlEngine, rpeEngine rpe.RpeEngine) {
+       for {
+               if <-triggerSBI {
+                       data, err := sdlEngine.ReadAll(*args["filename"])
+                       if err != nil || data == nil {
+                               rtmgr.Logger.Error("cannot get data from sdl interface due to: " + err.Error())
+                               continue
+                       }
+                       sbiEngine.UpdateEndpoints(data)
+                       policies := rpeEngine.GeneratePolicies(rtmgr.Eps)
+                       err = sbiEngine.DistributeAll(policies)
+                       if err != nil {
+                               rtmgr.Logger.Error("routing rable cannot be published due to: " + err.Error())
+                       }
+               }
+       }
+}
+
+func serve(nbiEngine nbi.NbiEngine, sbiEngine sbi.SbiEngine, sdlEngine sdl.SdlEngine, rpeEngine rpe.RpeEngine) {
+
+       triggerSBI := make(chan bool)
+
+       nbiErr := nbiEngine.Initialize(*args["xm-url"], *args["nbi-if"], *args["filename"], *args["configfile"],
+                                       sdlEngine, rpeEngine, triggerSBI)
+       if nbiErr != nil {
+               rtmgr.Logger.Error("fail to initialize nbi due to: " + nbiErr.Error())
+               return
+       }
+
+       err := sbiEngine.Initialize(*args["sbi-if"])
        if err != nil {
                rtmgr.Logger.Info("fail to open pub socket due to: " + err.Error())
                return
        }
        if err != nil {
                rtmgr.Logger.Info("fail to open pub socket due to: " + err.Error())
                return
        }
-       defer sbii.CloseSocket()
+       defer nbiEngine.Terminate()
+       defer sbiEngine.Terminate()
+
+       // This SBI Go routine is trtiggered by periodic main loop and when data is recieved on REST interface.
+       go serveSBI(triggerSBI, sbiEngine, sdlEngine, rpeEngine)
+
        for {
                time.Sleep(INTERVAL * time.Second)
        for {
                time.Sleep(INTERVAL * time.Second)
-               data, err := nbii.BatchFetch(*args["xm-url"])
-               if err != nil {
-                       rtmgr.Logger.Error("cannot get data from " + nbii.Engine.Name + " interface dute to: " + err.Error())
-               } else {
-                       sdli.WriteAll(*args["filename"], data)
-               }
-               data, err = sdli.ReadAll(*args["filename"])
-               if err != nil || data == nil {
-                       rtmgr.Logger.Error("cannot get data from " + sdli.Engine.Name + " interface dute to: " + err.Error())
-                       continue
-               }
-               sbi.UpdateEndpointList(data, sbii)
-               policies := rpei.GeneratePolicies(rtmgr.Eps)
-               err = sbii.DistributeAll(policies)
-               if err != nil {
-                       rtmgr.Logger.Error("routing rable cannot be published due to: " + err.Error())
+               if *args["nbi"] == "httpGetter" {
+                       data, err := nbiEngine.(*nbi.HttpGetter).FetchAllXapps(*args["xm-url"])
+                       if err != nil {
+                               rtmgr.Logger.Error("cannot fetch xapp data dute to: " + err.Error())
+                       } else if data != nil {
+                               sdlEngine.WriteXapps(*args["filename"], data)
+                       }
                }
                }
+
+               triggerSBI <- true
        }
 }
 
        }
 }
 
+func SetupCloseHandler() {
+       c := make(chan os.Signal, 2)
+       signal.Notify(c, os.Interrupt, syscall.SIGTERM)
+       go func() {
+               <-c
+               rtmgr.Logger.Info("\r- Ctrl+C pressed in Terminal")
+               os.Exit(0)
+       }()
+}
+
 func main() {
        parseArgs()
        rtmgr.SetLogLevel(*args["loglevel"])
 func main() {
        parseArgs()
        rtmgr.SetLogLevel(*args["loglevel"])
-       nbii, sbii, sdli, rpei, err := initRtmgr()
+       nbiEngine, sbiEngine, sdlEngine, rpeEngine, err := initRtmgr()
        if err != nil {
                rtmgr.Logger.Error(err.Error())
                os.Exit(1)
        }
        if err != nil {
                rtmgr.Logger.Error(err.Error())
                os.Exit(1)
        }
+       SetupCloseHandler()
        rtmgr.Logger.Info("Start " + SERVICENAME + " service")
        rtmgr.Eps = make(rtmgr.Endpoints)
        rtmgr.Logger.Info("Start " + SERVICENAME + " service")
        rtmgr.Eps = make(rtmgr.Endpoints)
-       serve(nbii, sbii, sdli, rpei)
+       serve(nbiEngine, sbiEngine, sdlEngine, rpeEngine)
        os.Exit(0)
 }
        os.Exit(0)
 }
index a13d479..5b938c6 100644 (file)
@@ -2,4 +2,4 @@
 # By default this file is in the docker build directory,
 # but the location can configured in the JJB template.
 ---
 # By default this file is in the docker build directory,
 # but the location can configured in the JJB template.
 ---
-tag: 0.1.0
+tag: 0.3.0
diff --git a/glide.lock b/glide.lock
new file mode 100644 (file)
index 0000000..ca9041f
--- /dev/null
@@ -0,0 +1,120 @@
+hash: f46d5840e1625820d08f8be64aad2627deaca8c33a33d5b90234a4212d01cf26
+updated: 2019-04-17T22:45:16.134234092+03:00
+imports:
+- name: github.com/asaskevich/govalidator
+  version: f9ffefc3facfbe0caee3fea233cbb6e8208f4541
+- name: github.com/docker/go-units
+  version: 2fb04c6466a548a03cb009c5569ee1ab1e35398e
+- name: github.com/droundy/goopt
+  version: 0b8effe182da161d81b011aba271507324ecb7ab
+- name: github.com/globalsign/mgo
+  version: eeefdecb41b842af6dc652aaea4026e8403e62df
+  subpackages:
+  - bson
+  - internal/json
+- name: github.com/go-openapi/analysis
+  version: e2f3fdbb7ed0e56e070ccbfb6fc75b288a33c014
+  subpackages:
+  - internal
+- name: github.com/go-openapi/errors
+  version: 7a7ff1b7b8020f22574411a32f28b4d168d69237
+- name: github.com/go-openapi/jsonpointer
+  version: ef5f0afec364d3b9396b7b77b43dbe26bf1f8004
+- name: github.com/go-openapi/jsonreference
+  version: 8483a886a90412cd6858df4ea3483dce9c8e35a3
+- name: github.com/go-openapi/loads
+  version: 74628589c3b94e3526a842d24f46589980f5ab22
+- name: github.com/go-openapi/runtime
+  version: 109737172424d8a656fd1199e28c9f5cc89b0cca
+  subpackages:
+  - flagext
+  - logger
+  - middleware
+  - middleware/denco
+  - middleware/header
+  - middleware/untyped
+  - security
+- name: github.com/go-openapi/spec
+  version: 53d776530bf78a11b03a7b52dd8a083086b045e5
+- name: github.com/go-openapi/strfmt
+  version: 29177d4b5db488583bb97ebc05d3842ebeda91a8
+- name: github.com/go-openapi/swag
+  version: b3e2804c8535ee0d1b89320afd98474d5b8e9e3b
+- name: github.com/go-openapi/validate
+  version: 5b1623be7460f5a3967a82c00d518048fb190f5e
+- name: github.com/gorilla/websocket
+  version: 66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d
+- name: github.com/jcelliott/lumber
+  version: dd349441af25132d146d7095c6693a15431fc9b1
+- name: github.com/jessevdk/go-flags
+  version: c6ca198ec95c841fdb89fc0de7496fed11ab854e
+- name: github.com/mailru/easyjson
+  version: 1ea4449da9834f4d333f1cc461c374aea217d249
+  subpackages:
+  - buffer
+  - jlexer
+  - jwriter
+- name: github.com/Microsoft/go-winio
+  version: 1a8911d1ed007260465c3bfbbc785ac6915a0bb8
+- name: github.com/mitchellh/mapstructure
+  version: 3536a929edddb9a5b34bd6861dc4a9647cb459fe
+- name: github.com/PuerkitoBio/purell
+  version: 44968752391892e1b0d0b821ee79e9a85fa13049
+- name: github.com/PuerkitoBio/urlesc
+  version: de5bf2ad457846296e2031421a34e2568e304e35
+- name: golang.org/x/net
+  version: 1da14a5a36f220ea3f03470682b737b1dfd5de22
+  subpackages:
+  - idna
+  - netutil
+- name: golang.org/x/sys
+  version: 12500544f89f9420afe9529ba8940bf72d294972
+  subpackages:
+  - windows
+- name: golang.org/x/text
+  version: f4905fbd45b6790792202848439271c74074bbfd
+  subpackages:
+  - secure/bidirule
+  - transform
+  - unicode/bidi
+  - unicode/norm
+  - width
+- name: gopkg.in/yaml.v2
+  version: 51d6538a90f86fe93ac480b35f37b2be17fef232
+- name: nanomsg.org/go/mangos/v2
+  version: 63f66a65137b9a648ac9f7bf0160b4a4d17d7999
+  subpackages:
+  - errors
+  - internal/core
+  - protocol
+  - protocol/bus
+  - protocol/pair
+  - protocol/pub
+  - protocol/pull
+  - protocol/push
+  - protocol/rep
+  - protocol/req
+  - protocol/respondent
+  - protocol/star
+  - protocol/sub
+  - protocol/surveyor
+  - protocol/xbus
+  - protocol/xpair
+  - protocol/xpub
+  - protocol/xpull
+  - protocol/xpush
+  - protocol/xrep
+  - protocol/xstar
+  - transport
+  - transport/all
+  - transport/inproc
+  - transport/ipc
+  - transport/tcp
+  - transport/tlstcp
+  - transport/ws
+  - transport/wss
+testImports:
+- name: github.com/smartystreets/goconvey
+  version: 68dc04aab96ae4326137d6b77330c224063a927e
+  subpackages:
+  - convey
similarity index 73%
rename from pkg/glide.yaml
rename to glide.yaml
index c7dd74c..cb916c3 100644 (file)
@@ -59,8 +59,38 @@ import:
   - transport/tlstcp
   - transport/ws
   - transport/wss
   - transport/tlstcp
   - transport/ws
   - transport/wss
+- package: github.com/go-openapi/errors
+  version: v0.19.0
+- package: github.com/go-openapi/loads
+  version: v0.19.0
+- package: github.com/go-openapi/runtime
+  version: v0.19.0
+  subpackages:
+  - flagext
+  - middleware
+  - security
+- package: github.com/go-openapi/spec
+  version: v0.19.0
+- package: github.com/go-openapi/strfmt
+  version: v0.19.0
+- package: github.com/go-openapi/swag
+  version: v0.19.0
+- package: github.com/go-openapi/validate
+  version: v0.19.0
+- package: github.com/jessevdk/go-flags
+  version: v1.4.0
+- package: github.com/jcelliott/lumber
 ignore:
 ignore:
+- models
 - rtmgr
 - rtmgr
+- restapi
+- nbi
+- sbi
+- rpe
+- sdl
+- appmgr_model
+- appmgr_client
+- stub
 testImport:
 - package: github.com/smartystreets/goconvey
   subpackages:
 testImport:
 - package: github.com/smartystreets/goconvey
   subpackages:
diff --git a/manifests/rtmgr/rtmgr-cfg.yaml b/manifests/rtmgr/rtmgr-cfg.yaml
new file mode 100644 (file)
index 0000000..65c6a6e
--- /dev/null
@@ -0,0 +1,54 @@
+#
+#==================================================================================
+#   Copyright (c) 2019 AT&T Intellectual Property.
+#   Copyright (c) 2019 Nokia
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#==================================================================================
+#
+#
+#   Abstract:           Configuration values for the routing manager
+#   Date:               29 May 2019
+#
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: rtmgrcfg
+data:
+  # FQDN and port info of the platform components for routing manager to form and distribute corresponding routes to them
+        rtmgrcfg: |
+                {
+                        "PlatformComponents":
+                        [
+                                {
+                                        "name": "E2TERM",
+                                        "fqdn": "e2term",
+                                        "port": 4561
+                                },
+                                {
+                                        "name": "SUBMAN",
+                                        "fqdn": "subman",
+                                        "port": 4561
+                                },
+                                {
+                                        "name": "E2MAN",
+                                        "fqdn": "e2man",
+                                        "port": 4561
+                                },
+                                {
+                                        "name": "UEMAN",
+                                        "fqdn": "ueman",
+                                        "port": 4561
+                                }
+                        ]
+                }
index 0a9982b..7dc475e 100644 (file)
@@ -24,7 +24,6 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: rtmgr
 kind: Deployment
 metadata:
   name: rtmgr
-  namespace: example
 spec:
   replicas: 1
   selector:
 spec:
   replicas: 1
   selector:
@@ -37,18 +36,39 @@ spec:
     spec:
       containers:
       - name: rtmgr
     spec:
       containers:
       - name: rtmgr
-        image: cmaster:5000/rtmgr:0.1.0
+        image: cmaster:5000/rtmgr:latest
         command: ["/run_rtmgr.sh"]
         env:
         - name: XMURL
         command: ["/run_rtmgr.sh"]
         env:
         - name: XMURL
-          value: "http://xmgr:3000/xapps"
-        - name: IP
-          value: "0.0.0.0"
+          value: "http://appmgr-service:8080/ric/v1/xapps"
         - name: RTFILE
           value: "/db/rt.json"
         - name: RPE
           value: "rmrpush"
         - name: SBI
           value: "nngpush"
         - name: RTFILE
           value: "/db/rt.json"
         - name: RPE
           value: "rmrpush"
         - name: SBI
           value: "nngpush"
+        - name: SBIURL
+          value: "0.0.0.0"
+        - name: NBI
+          value: "httpRESTful"
+        - name: NBIURL
+          value: "http://0.0.0.0:8888"
+        - name: CFGFILE
+          value: "/cfg/rtmgr-config.json"
+        - name: LOGLEVEL
+          value: "DEBUG"
         ports:
         ports:
+        - containerPort: 8888
         - containerPort: 4560
         - containerPort: 4560
+        volumeMounts:
+          - mountPath: /cfg
+            name: rtmgrcfg
+            readOnly: true
+      volumes:
+        - name: rtmgrcfg
+          configMap:
+            name: rtmgrcfg
+            items:
+              - key: rtmgrcfg
+                path: rtmgr-config.json
+                mode: 0644
index 78674be..bbb12a4 100644 (file)
@@ -24,7 +24,6 @@ kind: Service
 apiVersion: v1
 metadata:
   name: rtmgr
 apiVersion: v1
 metadata:
   name: rtmgr
-  namespace: example
 spec:
   selector:
     app: rtmgr
 spec:
   selector:
     app: rtmgr
diff --git a/pkg/glide.lock b/pkg/glide.lock
deleted file mode 100644 (file)
index 8c2f53c..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-hash: 8a251805c06cd6f4f20b276425eabe314968e2ad14fb32525fc93c53c2cfe845
-updated: 2019-04-04T20:26:54.485838082Z
-imports:
-- name: github.com/droundy/goopt
-  version: 0b8effe182da161d81b011aba271507324ecb7ab
-- name: github.com/gorilla/websocket
-  version: 66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d
-- name: github.com/jcelliott/lumber
-  version: dd349441af25132d146d7095c6693a15431fc9b1
-- name: github.com/Microsoft/go-winio
-  version: 1a8911d1ed007260465c3bfbbc785ac6915a0bb8
-- name: golang.org/x/sys
-  version: 81d4e9dc473e5e8c933f2aaeba2a3d81efb9aed2
-  subpackages:
-  - windows
-- name: nanomsg.org/go/mangos/v2
-  version: 63f66a65137b9a648ac9f7bf0160b4a4d17d7999
-  subpackages:
-  - errors
-  - internal/core
-  - protocol
-  - protocol/bus
-  - protocol/pair
-  - protocol/pub
-  - protocol/pull
-  - protocol/push
-  - protocol/rep
-  - protocol/req
-  - protocol/respondent
-  - protocol/star
-  - protocol/sub
-  - protocol/surveyor
-  - protocol/xbus
-  - protocol/xpair
-  - protocol/xpub
-  - protocol/xpull
-  - protocol/xpush
-  - protocol/xrep
-  - protocol/xstar
-  - transport
-  - transport/all
-  - transport/inproc
-  - transport/ipc
-  - transport/tcp
-  - transport/tlstcp
-  - transport/ws
-  - transport/wss
-testImports:
-- name: github.com/smartystreets/goconvey
-  version: 68dc04aab96ae4326137d6b77330c224063a927e
-  subpackages:
-  - convey
index 6780403..33db0f8 100644 (file)
@@ -28,23 +28,53 @@ package nbi
 import (
        "encoding/json"
        "net/http"
 import (
        "encoding/json"
        "net/http"
-       "rtmgr"
+       "routing-manager/pkg/rtmgr"
+       "routing-manager/pkg/rpe"
+       "routing-manager/pkg/sdl"
        "time"
 )
 
        "time"
 )
 
-var myClient = &http.Client{Timeout: 1 * time.Second}
+type HttpGetter struct {
+       NbiEngine
+       FetchAllXapps FetchAllXappsHandler
+}
+
+func NewHttpGetter() *HttpGetter {
+       instance := new(HttpGetter)
+       instance.FetchAllXapps = fetchAllXapps
+       return instance
+}
 
 
-func fetchXappList(url string) (*[]rtmgr.XApp, error) {
-       rtmgr.Logger.Debug("Invoked httpgetter.fetchXappList")
-       r, err := myClient.Get(url)
+var myClient = &http.Client{Timeout: 5 * time.Second}
+
+func fetchAllXapps(xmurl string) (*[]rtmgr.XApp, error) {
+       rtmgr.Logger.Info("Invoked httpgetter.fetchXappList: " + xmurl)
+       r, err := myClient.Get(xmurl)
        if err != nil {
                return nil, err
        }
        defer r.Body.Close()
        if err != nil {
                return nil, err
        }
        defer r.Body.Close()
-       rtmgr.Logger.Debug("http client raw response: %v", r)
-       var xapps []rtmgr.XApp
-       json.NewDecoder(r.Body).Decode(&xapps)
-       rtmgr.Logger.Info("HTTP GET: OK")
-       rtmgr.Logger.Debug("httpgetter.fetchXappList returns: %v", xapps)
-       return &xapps, err
+
+       if r.StatusCode == 200 {
+               rtmgr.Logger.Debug("http client raw response: %v", r)
+               var xapps []rtmgr.XApp
+               err = json.NewDecoder(r.Body).Decode(&xapps)
+               if err != nil {
+                       rtmgr.Logger.Warn("Json decode failed: " + err.Error())
+               }
+               rtmgr.Logger.Info("HTTP GET: OK")
+               rtmgr.Logger.Debug("httpgetter.fetchXappList returns: %v", xapps)
+               return &xapps, err
+       }
+       rtmgr.Logger.Warn("httpgetter got an unexpected http status code: %v", r.StatusCode)
+       return nil, nil
+}
+
+func (g *HttpGetter) Initialize(xmurl string, nbiif string, fileName string, configfile string,
+                               sdlEngine sdl.SdlEngine, rpeEngine rpe.RpeEngine, triggerSBI chan<- bool) error {
+       return nil
+}
+
+func (g *HttpGetter) Terminate() error {
+       return nil
 }
 }
diff --git a/pkg/nbi/httpgetter_test.go b/pkg/nbi/httpgetter_test.go
new file mode 100644 (file)
index 0000000..a6cbbf7
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+==================================================================================
+  Copyright (c) 2019 AT&T Intellectual Property.
+  Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+  Mnemonic:     httpgetter.go
+  Abstract:     HTTPgetter unit tests
+  Date:         14 May 2019
+*/
+
+package nbi
+
+import (
+       "net"
+       "net/http"
+       "net/http/httptest"
+       "routing-manager/pkg/rtmgr"
+       "testing"
+)
+
+var (
+       XMURL string = "http://127.0.0.1:3000/ric/v1/xapps"
+)
+
+
+func TestFetchXappListInvalidData(t *testing.T) {
+       var httpGetter = NewHttpGetter()
+        _, err := httpGetter.FetchAllXapps(XMURL)
+       if err == nil {
+               t.Error("No XApp data received: "+err.Error())
+       }
+}
+
+
+func TestFetchXappListWithInvalidData(t *testing.T) {
+       var expected int = 0
+       rtmgr.SetLogLevel("debug")
+       b := []byte(`{"ID":"deadbeef1234567890", "Version":0, "EventType":"all"}`)
+       l, err := net.Listen("tcp", "127.0.0.1:3000")
+       if err != nil {
+               t.Error("Failed to create listener: " + err.Error())
+       }
+       ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               //t.Log(r.Method)
+               //t.Log(r.URL)
+               if r.Method == "GET" && r.URL.String() == "/ric/v1/xapps" {
+                       //t.Log("Sending reply")
+                       w.Header().Add("Content-Type", "application/json")
+                       w.WriteHeader(http.StatusOK)
+                       w.Write(b)
+               }
+       }))
+       ts.Listener.Close()
+       ts.Listener = l
+
+       ts.Start()
+       defer ts.Close()
+       var httpGetter = NewHttpGetter()
+        xapplist, err := httpGetter.FetchAllXapps(XMURL)
+       if err == nil {
+               t.Error("Error occured: " + err.Error())
+       } else {
+               //t.Log(len(*xapplist))
+               if len(*xapplist) != expected {
+                       t.Error("Invalid XApp data: got " + string(len(*xapplist)) + ", expected " + string(expected))
+               }
+       }
+}
+
+func TestFetchAllXappsWithValidData(t *testing.T) {
+       var expected int = 1
+       b := []byte(`[
+ {
+ "name":"xapp-01","status":"unknown","version":"1.2.3",
+    "instances":[
+        {"name":"xapp-01-instance-01","status":"pending","ip":"172.16.1.103","port":4555,
+            "txMessages":["ControlIndication"],
+            "rxMessages":["LoadIndication","Reset"]
+        },
+        {"name":"xapp-01-instance-02","status":"pending","ip":"10.244.1.12","port":4561,
+            "txMessages":["ControlIndication","SNStatusTransfer"],
+            "rxMessages":["LoadIndication","HandoverPreparation"]
+        }
+    ]
+}
+]`)
+       l, err := net.Listen("tcp", "127.0.0.1:3000")
+       if err != nil {
+               t.Error("Failed to create listener: " + err.Error())
+       }
+       ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               //t.Log(r.Method)
+               //t.Log(r.URL)
+               if r.Method == "GET" && r.URL.String() == "/ric/v1/xapps" {
+                       //t.Log("Sending reply")
+                       w.Header().Add("Content-Type", "application/json")
+                       w.WriteHeader(http.StatusOK)
+                       w.Write(b)
+               }
+       }))
+       ts.Listener.Close()
+       ts.Listener = l
+
+       ts.Start()
+       defer ts.Close()
+       var httpGetter = NewHttpGetter()
+       xapplist, err := httpGetter.FetchAllXapps(XMURL)
+       if err != nil {
+               t.Error("Error occured: " + err.Error())
+       } else {
+               if len(*xapplist) != expected {
+                       t.Error("Invalid XApp data: got " + string(len(*xapplist)) + ", expected " + string(expected))
+               }
+       }
+}
+
diff --git a/pkg/nbi/httprestful.go b/pkg/nbi/httprestful.go
new file mode 100644 (file)
index 0000000..4b936a6
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+==================================================================================
+  Copyright (c) 2019 AT&T Intellectual Property.
+  Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+  Mnemonic:    httprestful.go
+  Abstract:    HTTP Restful API NBI implementation
+                Based on Swagger generated code
+  Date:                25 March 2019
+*/
+
+package nbi
+
+import (
+       "fmt"
+       "os"
+       "time"
+       "net/url"
+       "strconv"
+       "errors"
+       "encoding/json"
+       "routing-manager/pkg/rtmgr"
+       "routing-manager/pkg/rpe"
+       "routing-manager/pkg/sdl"
+       "routing-manager/pkg/models"
+       "routing-manager/pkg/restapi"
+       "routing-manager/pkg/restapi/operations"
+       "github.com/go-openapi/runtime/middleware"
+       "routing-manager/pkg/restapi/operations/handle"
+       loads "github.com/go-openapi/loads"
+)
+
+//var myClient = &http.Client{Timeout: 1 * time.Second}
+
+type HttpRestful struct {
+       NbiEngine
+       LaunchRest                   LaunchRestHandler
+       RecvXappCallbackData         RecvXappCallbackDataHandler
+       ProvideXappHandleHandlerImpl ProvideXappHandleHandlerImpl
+       RetrieveStartupData          RetrieveStartupDataHandler
+}
+
+func NewHttpRestful() *HttpRestful {
+       instance := new(HttpRestful)
+       instance.LaunchRest = launchRest
+       instance.RecvXappCallbackData = recvXappCallbackData
+       instance.ProvideXappHandleHandlerImpl = provideXappHandleHandlerImpl
+       instance.RetrieveStartupData = retrieveStartupData
+       return instance
+}
+
+// ToDo: Use Range over channel. Read and return only the latest one.
+func recvXappCallbackData(dataChannel <-chan *models.XappCallbackData) (*[]rtmgr.XApp, error) {
+       var xappData *models.XappCallbackData
+       // Drain the channel as we are only looking for the latest value until
+       // xapp manager sends all xapp data with every request.
+       length := len(dataChannel)
+       //rtmgr.Logger.Info(length)
+       for i := 0; i <= length; i++ {
+               rtmgr.Logger.Info("data received")
+               // If no data received from the REST, it blocks.
+               xappData = <-dataChannel
+       }
+       if nil != xappData {
+                var xapps []rtmgr.XApp
+                err := json.Unmarshal([]byte(xappData.Data), &xapps)
+               return &xapps, err
+       } else {
+               rtmgr.Logger.Info("No data")
+       }
+
+       rtmgr.Logger.Debug("Nothing received on the Http interface")
+       return nil, nil
+
+}
+
+func validateXappCallbackData(callbackData *models.XappCallbackData) error {
+       if len(callbackData.Data) == 0 {
+               return fmt.Errorf("Invalid Data field: \"%s\"", callbackData.Data)
+       }
+       var xapps []rtmgr.XApp
+        err := json.Unmarshal([]byte(callbackData.Data), &xapps)
+        if err != nil {
+               return fmt.Errorf("Unmarshal failed: \"%s\"", err.Error())
+       }
+       return nil
+}
+
+func provideXappHandleHandlerImpl(datach chan<- *models.XappCallbackData, data *models.XappCallbackData) error {
+       if data != nil {
+               rtmgr.Logger.Debug("Received callback data")
+       }
+       err := validateXappCallbackData(data)
+       if err != nil {
+               rtmgr.Logger.Debug("XApp callback data validation failed: "+err.Error())
+               return err
+       } else {
+               datach<-data
+               return nil
+       }
+}
+
+func validateXappSubscriptionData(data *models.XappSubscriptionData) error {
+       var err = fmt.Errorf("XApp instance not found: %v:%v", *data.Address, *data.Port)
+       for _, ep := range rtmgr.Eps {
+               if ep.Ip == *data.Address && ep.Port == *data.Port {
+                       err = nil
+                       break
+               }
+       }
+       return err
+}
+
+func provideXappSubscriptionHandleImpl(subchan chan<- *models.XappSubscriptionData,
+                                       data *models.XappSubscriptionData) error {
+       rtmgr.Logger.Debug("Invoked provideXappSubscriptionHandleImpl")
+       err := validateXappSubscriptionData(data)
+       if err != nil {
+               rtmgr.Logger.Error(err.Error())
+               return err
+       }
+       subchan <- data
+       //var val = string(*data.Address + ":" + strconv.Itoa(int(*data.Port)))
+       rtmgr.Logger.Debug("Endpoints: %v", rtmgr.Eps)
+       return nil
+}
+
+func launchRest(nbiif *string, datach chan<- *models.XappCallbackData, subchan chan<- *models.XappSubscriptionData) {
+        swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
+        if err != nil {
+                //log.Fatalln(err)
+                rtmgr.Logger.Error(err.Error())
+                os.Exit(1)
+        }
+       nbiUrl, err := url.Parse(*nbiif)
+       if err != nil {
+               rtmgr.Logger.Error(err.Error())
+               os.Exit(1)
+       }
+        api := operations.NewRoutingManagerAPI(swaggerSpec)
+        server := restapi.NewServer(api)
+        defer server.Shutdown()
+
+        server.Port, err = strconv.Atoi(nbiUrl.Port())
+        if err != nil {
+               rtmgr.Logger.Error("Invalid NBI RestAPI port")
+               os.Exit(1)
+        }
+        server.Host = nbiUrl.Hostname()
+        // set handlers
+        api.HandleProvideXappHandleHandler = handle.ProvideXappHandleHandlerFunc(
+                func(params handle.ProvideXappHandleParams) middleware.Responder {
+                rtmgr.Logger.Info("Data received on Http interface")
+               err := provideXappHandleHandlerImpl(datach, params.XappCallbackData)
+               if err != nil {
+                       rtmgr.Logger.Error("Invalid XApp callback data: "+err.Error())
+                       return handle.NewProvideXappHandleBadRequest()
+               } else {
+                       return handle.NewGetHandlesOK()
+               }
+        })
+       api.HandleProvideXappSubscriptionHandleHandler = handle.ProvideXappSubscriptionHandleHandlerFunc(
+               func(params handle.ProvideXappSubscriptionHandleParams) middleware.Responder {
+                       err := provideXappSubscriptionHandleImpl(subchan, params.XappSubscriptionData)
+                       if err != nil {
+                               return handle.NewProvideXappSubscriptionHandleBadRequest()
+                       } else {
+                               return handle.NewGetHandlesOK()
+                       }
+               })
+        // start to serve API
+        rtmgr.Logger.Info("Starting the HTTP Rest service")
+        if err := server.Serve(); err != nil {
+                rtmgr.Logger.Error(err.Error())
+        }
+}
+
+func httpGetXapps(xmurl string) (*[]rtmgr.XApp, error) {
+        rtmgr.Logger.Info("Invoked httpgetter.fetchXappList: " + xmurl)
+        r, err := myClient.Get(xmurl)
+        if err != nil {
+                return nil, err
+        }
+        defer r.Body.Close()
+
+        if r.StatusCode == 200 {
+                rtmgr.Logger.Debug("http client raw response: %v", r)
+                var xapps []rtmgr.XApp
+                err = json.NewDecoder(r.Body).Decode(&xapps)
+                if err != nil {
+                        rtmgr.Logger.Warn("Json decode failed: " + err.Error())
+                }
+                rtmgr.Logger.Info("HTTP GET: OK")
+                rtmgr.Logger.Debug("httpgetter.fetchXappList returns: %v", xapps)
+                return &xapps, err
+        }
+        rtmgr.Logger.Warn("httpgetter got an unexpected http status code: %v", r.StatusCode)
+        return nil, nil
+}
+
+func retrieveStartupData(xmurl string, nbiif string, fileName string, configfile string, sdlEngine sdl.SdlEngine) error {
+        var readErr error
+        var maxRetries = 10
+
+                for i := 1; i <= maxRetries; i++ {
+                        time.Sleep(2 * time.Second)
+
+                        xappData, err := httpGetXapps(xmurl)
+
+                        if xappData != nil && err == nil {
+                               pcData, confErr := rtmgr.GetPlatformComponents(configfile)
+                               if confErr != nil {
+                                       rtmgr.Logger.Error(confErr.Error())
+                                       return confErr
+                               }
+
+                                rtmgr.Logger.Info("Recieved intial xapp data and platform data, writing into SDL.")
+                               // Combine the xapps data and platform data before writing to the SDL
+                               ricData := &rtmgr.RicComponents{Xapps: *xappData, Pcs: *pcData}
+
+                                writeErr := sdlEngine.WriteAll(fileName, ricData)
+                                if writeErr != nil {
+                                        rtmgr.Logger.Error(writeErr.Error())
+                                }
+                                // post subscription req to appmgr
+                                readErr = PostSubReq(xmurl, nbiif)
+                                if readErr == nil {
+                                        return nil
+                                }
+                        } else if err == nil {
+                                readErr = errors.New("Unexpected HTTP status code")
+                        } else {
+                                rtmgr.Logger.Warn("cannot get xapp data due to: " + err.Error())
+                                readErr = err
+                        }
+                }
+        return readErr
+}
+
+func (r *HttpRestful) Initialize(xmurl string, nbiif string, fileName string, configfile string,
+                                sdlEngine sdl.SdlEngine, rpeEngine rpe.RpeEngine, triggerSBI chan<- bool) error {
+       err := r.RetrieveStartupData(xmurl, nbiif, fileName, configfile, sdlEngine)
+       if err != nil {
+               rtmgr.Logger.Error("Exiting as nbi failed to get the intial startup data from the xapp manager: " + err.Error())
+               return err
+       }
+
+       datach := make(chan *models.XappCallbackData, 10)
+       subschan := make(chan *models.XappSubscriptionData, 10)
+       rtmgr.Logger.Info("Launching Rest Http service")
+       go func() {
+               r.LaunchRest(&nbiif, datach, subschan)
+       }()
+
+       go func() {
+               for {
+                       data, err := r.RecvXappCallbackData(datach)
+                       if err != nil {
+                               rtmgr.Logger.Error("cannot get data from rest api dute to: " + err.Error())
+                       } else if data != nil {
+                               sdlEngine.WriteXapps(fileName, data)
+                               triggerSBI <- true
+                       }
+               }
+       }()
+       go func() {
+               for {
+                       data := <-subschan
+                       rtmgr.Logger.Debug("received XApp subscription data")
+                       addSubscription(&rtmgr.Subs, data)
+                       triggerSBI <- true
+               }
+       }()
+
+       return nil
+}
+
+func (r *HttpRestful) Terminate() error {
+       return nil
+}
+
+func addSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
+       var b bool = false
+       sub := rtmgr.Subscription{SubID:*xappSubData.SubscriptionID, Fqdn:*xappSubData.Address, Port:*xappSubData.Port,}
+       for _, elem := range *subs {
+               if elem == sub {
+                       rtmgr.Logger.Warn("rtmgr.addSubscription: Subscription already present: %v", elem)
+                       b = true
+               }
+       }
+       if b == false {
+               *subs = append(*subs, sub)
+       }
+       return b
+}
+
diff --git a/pkg/nbi/httprestful_test.go b/pkg/nbi/httprestful_test.go
new file mode 100644 (file)
index 0000000..137e75b
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+==================================================================================
+  Copyright (c) 2019 AT&T Intellectual Property.
+  Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+  Mnemonic:     httprestful_test.go
+  Abstract:     HTTPRestful unit tests
+  Date:         15 May 2019
+*/
+
+package nbi
+
+import (
+       "routing-manager/pkg/stub"
+        "routing-manager/pkg/models"
+        "routing-manager/pkg/sdl"
+       "github.com/go-openapi/swag"
+        "testing"
+       "time"
+        "net"
+        "net/http"
+        "net/http/httptest"
+       "fmt"
+       "os"
+       "io/ioutil"
+       "encoding/json"
+)
+
+var BASIC_XAPPLIST = []byte(`[
+ {
+ "name":"xapp-01","status":"unknown","version":"1.2.3",
+    "instances":[
+        {"name":"xapp-01-instance-01","status":"pending","ip":"172.16.1.103","port":4555,
+            "txMessages":["ControlIndication"],
+            "rxMessages":["LoadIndication","Reset"]
+        },
+        {"name":"xapp-01-instance-02","status":"pending","ip":"10.244.1.12","port":4561,
+            "txMessages":["ControlIndication","SNStatusTransfer"],
+            "rxMessages":["LoadIndication","HandoverPreparation"]
+        }
+    ]
+}
+]`)
+
+var SUBSCRIPTION_RESP = []byte(`{"ID":"deadbeef1234567890", "Version":0, "EventType":"all"}`)
+
+
+var INVALID_SUB_RESP = []byte(`{"Version":0, "EventType":all}`)
+
+
+func createMockAppmgrWithData(url string, g []byte, p []byte) *httptest.Server {
+       l, err := net.Listen("tcp", url)
+       if err != nil {
+               fmt.Println("Failed to create listener: " + err.Error())
+       }
+       ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               if r.Method == "GET" && r.URL.String() == "/ric/v1/xapps" {
+                       w.Header().Add("Content-Type", "application/json")
+                       w.WriteHeader(http.StatusOK)
+                       w.Write(g)
+               }
+               if r.Method == "POST" && r.URL.String() == "/ric/v1/subscriptions" {
+                        w.Header().Add("Content-Type", "application/json")
+                        w.WriteHeader(http.StatusCreated)
+                        w.Write(p)
+                }
+
+       }))
+       ts.Listener.Close()
+       ts.Listener = l
+       return ts
+}
+
+func createMockPlatformComponents() {
+       var filename = string("config.json")
+       file, _ := json.MarshalIndent(stub.ValidPlatformComponents, "", "")
+       filestr := string(file)
+       filestr = "{\"PlatformComponents\":"+filestr+"}"
+       file = []byte(filestr)
+       _ = ioutil.WriteFile(filename, file, 644)
+}
+
+func TestRecvXappCallbackData(t *testing.T) {
+       data := models.XappCallbackData {
+                Data: *swag.String("[]"),
+                DataVersion: *swag.Int64(1),
+                Event: *swag.String("any"),
+                ID: *swag.Int64(123456),
+       }
+
+       ch := make(chan *models.XappCallbackData)
+       defer close(ch)
+       httpRestful := NewHttpRestful()
+       go func() {ch<- &data}()
+       time.Sleep(1 * time.Second)
+       t.Log(string(len(ch)))
+       xappList, err := httpRestful.RecvXappCallbackData(ch)
+       if err != nil {
+               t.Error("Receive failed: "+err.Error())
+       } else {
+               if xappList == nil {
+                       t.Error("Expected an XApp notification list")
+               } else {
+                       t.Log("whatever")
+               }
+       }
+}
+
+func TestProvideXappHandleHandlerImpl(t *testing.T) {
+       datach := make(chan *models.XappCallbackData, 10)
+       defer close(datach)
+       data := models.XappCallbackData{
+               Data: *swag.String("[]"),
+               DataVersion: *swag.Int64(1),
+               Event: *swag.String("someevent"),
+               ID: *swag.Int64(123456)}
+       var httpRestful, _ = GetNbi("httpRESTful")
+       err := httpRestful.(*HttpRestful).ProvideXappHandleHandlerImpl(datach, &data)
+       if err != nil {
+               t.Error("Error occured: "+err.Error())
+       } else {
+               recv := <-datach
+               if recv == nil {
+                       t.Error("Something gone wrong: "+err.Error())
+               } else {
+                       if recv != &data {
+                               t.Error("Malformed data on channel")
+                       }
+               }
+       }
+}
+
+func TestValidateXappCallbackData(t *testing.T) {
+        data := models.XappCallbackData{
+                Data: *swag.String("[]"),
+                DataVersion: *swag.Int64(1),
+                Event: *swag.String("someevent"),
+                ID: *swag.Int64(123456)}
+
+       err := validateXappCallbackData(&data)
+       if err != nil {
+               t.Error("Invalid XApp callback data: "+err.Error())
+       }
+}
+
+func TestValidateXappCallbackDataWithInvalidData(t *testing.T) {
+        data := models.XappCallbackData{
+                Data: *swag.String("{}"),
+                DataVersion: *swag.Int64(1),
+                Event: *swag.String("someevent"),
+                ID: *swag.Int64(123456)}
+
+        err := validateXappCallbackData(&data)
+        if err == nil {
+                t.Error("Invalid XApp callback data: "+err.Error())
+        }
+}
+
+
+func TestHttpGetXappsInvalidData(t *testing.T) {
+        _, err := httpGetXapps(XMURL)
+        if err == nil {
+                t.Error("No XApp data received: "+err.Error())
+        }
+}
+
+func TestHttpGetXappsWithValidData(t *testing.T) {
+       var expected int = 1
+       ts := createMockAppmgrWithData("127.0.0.1:3000", BASIC_XAPPLIST, nil)
+
+       ts.Start()
+       defer ts.Close()
+       xapplist, err := httpGetXapps(XMURL)
+       if err != nil {
+               t.Error("Error occured: " + err.Error())
+       } else {
+               if len(*xapplist) != expected {
+                       t.Error("Invalid XApp data: got " + string(len(*xapplist)) + ", expected " + string(expected))
+               }
+       }
+}
+
+func TestRetrieveStartupDataTimeout(t *testing.T) {
+       sdlEngine, _ := sdl.GetSdl("file")
+       createMockPlatformComponents()
+       err := retrieveStartupData(XMURL, "httpgetter","rt.json", "config.json", sdlEngine)
+       if err == nil {
+               t.Error("Cannot retrieve startup data: "+err.Error())
+       }
+       os.Remove("rt.json")
+       os.Remove("config.json")
+}
+
+func TestRetrieveStartupData(t *testing.T) {
+       ts := createMockAppmgrWithData("127.0.0.1:3000", BASIC_XAPPLIST, SUBSCRIPTION_RESP)
+       ts.Start()
+       defer ts.Close()
+        sdlEngine, _ := sdl.GetSdl("file")
+       var httpRestful, _ = GetNbi("httpRESTful")
+       createMockPlatformComponents()
+       err := httpRestful.(*HttpRestful).RetrieveStartupData(XMURL, "httpgetter", "rt.json","config.json", sdlEngine)
+        //err := retrieveStartupData(XMURL, "httpgetter", "rt.json", "config.json", sdlEngine)
+        if err != nil {
+                t.Error("Cannot retrieve startup data: "+err.Error())
+        }
+       os.Remove("rt.json")
+       os.Remove("config.json")
+}
+
+func TestRetrieveStartupDataWithInvalidSubResp(t *testing.T) {
+       ts := createMockAppmgrWithData("127.0.0.1:3000", BASIC_XAPPLIST, INVALID_SUB_RESP)
+       ts.Start()
+       defer ts.Close()
+        sdlEngine, _ := sdl.GetSdl("file")
+       var httpRestful, _ = GetNbi("httpRESTful")
+       createMockPlatformComponents()
+        err := httpRestful.(*HttpRestful).RetrieveStartupData(XMURL, "httpgetter", "rt.json", "config.json", sdlEngine)
+        if err == nil {
+                t.Error("Cannot retrieve startup data: "+err.Error())
+        }
+       os.Remove("rt.json")
+       os.Remove("config.json")
+}
index 84282bd..bb0f485 100644 (file)
@@ -26,56 +26,87 @@ package nbi
 
 import (
        "errors"
 
 import (
        "errors"
-       "fmt"
-       "rtmgr"
+       "routing-manager/pkg/rtmgr"
+        "net/url"
+        apiclient "routing-manager/pkg/appmgr_client"
+        "routing-manager/pkg/appmgr_client/operations"
+        "routing-manager/pkg/appmgr_model"
+        httptransport "github.com/go-openapi/runtime/client"
+        "github.com/go-openapi/strfmt"
+        "github.com/go-openapi/swag"
+        "time"
+
 )
 
 var (
        SupportedNbis = []*NbiEngineConfig{
                &NbiEngineConfig{
 )
 
 var (
        SupportedNbis = []*NbiEngineConfig{
                &NbiEngineConfig{
-                       NbiEngine{
-                               Name:     "httpGetter",
-                               Version:  "v1",
-                               Protocol: "http",
-                       },
-                       batchFetch(fetchXappList),
-                       true,
-               },
-               &NbiEngineConfig{
-                       NbiEngine{
-                               Name:     "httpRESTful",
-                               Version:  "v1",
-                               Protocol: "http",
-                       },
-                       batchFetch(nil),
-                       false,
+                       Name:     "httpGetter",
+                       Version:  "v1",
+                       Protocol: "http",
+                       Instance: NewHttpGetter(),
+                       IsAvailable: true,
                },
                &NbiEngineConfig{
                },
                &NbiEngineConfig{
-                       NbiEngine{
-                               Name:     "gRPC",
-                               Version:  "v1",
-                               Protocol: "http2",
-                       },
-                       batchFetch(nil),
-                       false,
+                       Name:     "httpRESTful",
+                       Version:  "v1",
+                       Protocol: "http",
+                       Instance: NewHttpRestful(),
+                       IsAvailable: true,
                },
        }
 )
 
                },
        }
 )
 
-func ListNbis() {
-       fmt.Printf("NBI:\n")
-       for _, nbi := range SupportedNbis {
-               if nbi.IsAvailable {
-                       rtmgr.Logger.Info(nbi.Engine.Name + "/" + nbi.Engine.Version)
-               }
-       }
+type Nbi struct {
+
 }
 
 }
 
-func GetNbi(nbiName string) (*NbiEngineConfig, error) {
+func GetNbi(nbiName string) (NbiEngine, error) {
        for _, nbi := range SupportedNbis {
        for _, nbi := range SupportedNbis {
-               if nbi.Engine.Name == nbiName && nbi.IsAvailable {
-                       return nbi, nil
+               if nbi.Name == nbiName && nbi.IsAvailable {
+                       return nbi.Instance, nil
                }
        }
        return nil, errors.New("NBI:" + nbiName + " is not supported or still not a available")
 }
                }
        }
        return nil, errors.New("NBI:" + nbiName + " is not supported or still not a available")
 }
+
+func CreateSubReq(restUrl string, restPort string) *appmgr_model.SubscriptionRequest {
+       // TODO: parametize function
+        subReq := appmgr_model.SubscriptionRequest{
+                TargetURL:  swag.String(restUrl + ":" + restPort + "/ric/v1/handles/xapp-handle/"),
+                EventType:  swag.String("all"),
+                MaxRetries: swag.Int64(5),
+                RetryTimer: swag.Int64(10),
+        }
+
+        return &subReq
+}
+
+func PostSubReq(xmUrl string, nbiif string) error {
+        // setting up POST request to Xapp Manager
+        appmgrUrl, err := url.Parse(xmUrl)
+        if err != nil {
+                rtmgr.Logger.Error("Invalid XApp manager url/hostname: " + err.Error())
+                return err
+        }
+       nbiifUrl, err := url.Parse(nbiif)
+       if err != nil {
+               rtmgr.Logger.Error("Invalid NBI address/port: " + err.Error())
+               return err
+       }
+        transport := httptransport.New(appmgrUrl.Hostname()+":"+appmgrUrl.Port(), "/ric/v1", []string{"http"})
+        client := apiclient.New(transport, strfmt.Default)
+        addSubParams := operations.NewAddSubscriptionParamsWithTimeout(10 * time.Second)
+        // create sub req with rest url and port
+        subReq := CreateSubReq(nbiifUrl.Hostname(), nbiifUrl.Port())
+        resp, postErr := client.Operations.AddSubscription(addSubParams.WithSubscriptionRequest(subReq))
+        if postErr != nil {
+                rtmgr.Logger.Error("POST unsuccessful:"+postErr.Error())
+                return postErr
+        } else {
+                // TODO: use the received ID
+                rtmgr.Logger.Info("POST received: "+string(resp.Payload.ID))
+                return nil
+        }
+}
+
diff --git a/pkg/nbi/nbi_test.go b/pkg/nbi/nbi_test.go
new file mode 100644 (file)
index 0000000..a3aa836
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+==================================================================================
+  Copyright (c) 2019 AT&T Intellectual Property.
+  Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+  Mnemonic:     nbi_test.go
+  Abstract:     NBI unit tests
+  Date:         21 May 2019
+*/
+
+package nbi
+
+import (
+       "testing"
+       "reflect"
+       "errors"
+       "routing-manager/pkg/appmgr_model"
+       "github.com/go-openapi/swag"
+       "net"
+       "net/http"
+       "net/http/httptest"
+)
+
+func TestGetNbi(t *testing.T) {
+       var errtype = errors.New("")
+       var nbitype = new(HttpGetter)
+       var invalids = []string{"httpgetter", ""}
+
+       nbii, err := GetNbi("httpGetter")
+       if err != nil {
+               t.Errorf("GetNbi(HttpGetter) was incorrect, got: %v, want: %v.", reflect.TypeOf(err), nil)
+       }
+       if reflect.TypeOf(nbii) != reflect.TypeOf(nbitype) {
+               t.Errorf("GetNbi(HttpGetter) was incorrect, got: %v, want: %v.", reflect.TypeOf(nbii), reflect.TypeOf(nbitype))
+       }
+
+       for _, arg := range invalids {
+               _, err := GetNbi(arg)
+               if err == nil {
+                       t.Errorf("GetNbi("+arg+") was incorrect, got: %v, want: %v.", reflect.TypeOf(err), reflect.TypeOf(errtype))
+               }
+       }
+}
+
+func TestCreateSubReq(t *testing.T) {
+       var subReq = appmgr_model.SubscriptionRequest{
+                TargetURL:  swag.String("localhost:8000/ric/v1/handles/xapp-handle/"),
+                EventType:  swag.String("all"),
+                MaxRetries: swag.Int64(5),
+                RetryTimer: swag.Int64(10),
+        }
+       subReq2 := CreateSubReq("localhost","8000")
+       if reflect.TypeOf(subReq) != reflect.TypeOf(*subReq2) {
+               t.Errorf("Invalid type, got: %v, want: %v.", reflect.TypeOf(subReq), reflect.TypeOf(*subReq2))
+       }
+       if *(subReq.TargetURL) != *(subReq2.TargetURL) {
+               t.Errorf("Invalid TargetURL generated, got %v, want %v", *subReq.TargetURL, *subReq2.TargetURL)
+       }
+        if *(subReq.EventType) != *(subReq2.EventType) {
+                t.Errorf("Invalid EventType generated, got %v, want %v", *subReq.EventType, *subReq2.EventType)
+        }
+        if *(subReq.MaxRetries) != *(subReq2.MaxRetries) {
+                t.Errorf("Invalid MaxRetries generated, got %v, want %v", *subReq.MaxRetries, *subReq2.MaxRetries)
+        }
+        if *(subReq.RetryTimer) != *(subReq2.RetryTimer) {
+                t.Errorf("Invalid RetryTimer generated, got %v, want %v", *subReq.RetryTimer, *subReq2.RetryTimer)
+        }
+}
+
+func TestPostSubReq(t *testing.T) {
+       b := []byte(`{"ID":"deadbeef1234567890", "Version":0, "EventType":"all"}`)
+       l, err := net.Listen("tcp", "127.0.0.1:3000")
+        if err != nil {
+                t.Error("Failed to create listener: " + err.Error())
+        }
+        ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+                t.Log(r.Method)
+                t.Log(r.URL)
+                if r.Method == "POST" && r.URL.String() == "/ric/v1/subscriptions" {
+                        t.Log("Sending reply")
+                        w.Header().Add("Content-Type", "application/json")
+                        w.WriteHeader(http.StatusCreated)
+                        w.Write(b)
+                }
+        }))
+        ts.Listener.Close()
+        ts.Listener = l
+
+        ts.Start()
+       defer ts.Close()
+       err = PostSubReq("http://127.0.0.1:3000/ric/v1/subscription","localhost:8888")
+       if err != nil {
+               t.Error("Error occured: "+err.Error())
+       }
+}
+
+func TestPostSubReqWithInvalidUrls(t *testing.T) {
+       // invalid Xapp Manager URL
+        err := PostSubReq("http://127.0","http://localhost:8888")
+        if err == nil {
+                t.Error("Error occured: "+err.Error())
+        }
+       // invalid rest api url
+       err = PostSubReq("http://127.0.0.1:3000/","localhost:8888")
+       if err == nil {
+               t.Error("Error occured: "+err.Error())
+       }
+}
+
index e02c30d..2b4bebb 100644 (file)
 
 package nbi
 
 
 package nbi
 
-import "rtmgr"
-
-type batchFetch func(url string) (*[]rtmgr.XApp, error)
-
-type NbiEngine struct {
-       Name     string
-       Version  string
-       Protocol string
-}
+import (
+       "routing-manager/pkg/rtmgr"
+       "routing-manager/pkg/models"
+       "routing-manager/pkg/rpe"
+       "routing-manager/pkg/sdl"
+)
+
+type FetchAllXappsHandler func(string) (*[]rtmgr.XApp, error)
+type RecvXappCallbackDataHandler func(<-chan *models.XappCallbackData) (*[]rtmgr.XApp, error)
+type LaunchRestHandler func(*string, chan<- *models.XappCallbackData, chan<- *models.XappSubscriptionData)
+type ProvideXappHandleHandlerImpl func(chan<- *models.XappCallbackData, *models.XappCallbackData) (error)
+type RetrieveStartupDataHandler func(string, string, string, string, sdl.SdlEngine) error
 
 type NbiEngineConfig struct {
 
 type NbiEngineConfig struct {
-       Engine      NbiEngine
-       BatchFetch  batchFetch
+       Name        string
+       Version     string
+       Protocol    string
+       Instance    NbiEngine
        IsAvailable bool
 }
        IsAvailable bool
 }
+
+type NbiEngine interface {
+       Initialize(string, string, string, string, sdl.SdlEngine, rpe.RpeEngine, chan<- bool) error
+       Terminate() error
+}
+
index ca16772..41c1c4c 100644 (file)
 package rpe
 
 import (
 package rpe
 
 import (
-       "rtmgr"
+       "routing-manager/pkg/rtmgr"
        "strconv"
 )
 
        "strconv"
 )
 
+type Rmr struct {
+       Rpe
+}
+
+type RmrPub struct {
+       Rmr
+}
+
+type RmrPush struct {
+       Rmr
+}
+
+func NewRmrPub() *RmrPub {
+       instance := new(RmrPub)
+       return instance
+}
+
+func NewRmrPush() *RmrPush {
+       instance := new(RmrPush)
+       return instance
+}
+
 /*
 Produces the raw route message consumable by RMR
 */
 /*
 Produces the raw route message consumable by RMR
 */
-func generateRMRPolicies(eps rtmgr.Endpoints, key string) *[]string {
-       rtmgr.Logger.Debug("Invoked rmr.generateRMRPolicies")
-       rtmgr.Logger.Debug("args: %v", eps)
+func (r *Rmr) generateRMRPolicies(eps rtmgr.Endpoints, key string) *[]string {
        rawrt := []string{key + "newrt|start\n"}
        rawrt := []string{key + "newrt|start\n"}
-       rt := getRouteTable(eps)
+       rt := r.getRouteTable(eps)
        for _, rte := range *rt {
        for _, rte := range *rt {
-               rawrte := key + "rte|" + rte.MessageType
+               rawrte := key //+ "rte|" + rte.MessageType
+               if rte.SubID == -1 {
+                       rawrte += "rte|"
+               } else {
+                       rawrte += "mse|"
+               }
+               rawrte += rte.MessageType
                for _, tx := range rte.TxList {
                        rawrte += "," + tx.Ip + ":" + strconv.Itoa(int(tx.Port))
                }
                for _, tx := range rte.TxList {
                        rawrte += "," + tx.Ip + ":" + strconv.Itoa(int(tx.Port))
                }
-               rawrte += "|"
+               rawrte += "|" + strconv.Itoa(int(rte.SubID)) + "|"
                group := ""
                for _, rxg := range rte.RxGroups {
                        member := ""
                group := ""
                for _, rxg := range rte.RxGroups {
                        member := ""
@@ -64,14 +90,25 @@ func generateRMRPolicies(eps rtmgr.Endpoints, key string) *[]string {
                rawrt = append(rawrt, rawrte+"\n")
        }
        rawrt = append(rawrt, key+"newrt|end\n")
                rawrt = append(rawrt, rawrte+"\n")
        }
        rawrt = append(rawrt, key+"newrt|end\n")
-       rtmgr.Logger.Debug("rmr.generateRMRPolicies returns: %v", rawrt)
+       rtmgr.Logger.Debug("rmr.GeneratePolicies returns: %v", rawrt)
        return &rawrt
 }
 
        return &rawrt
 }
 
-func generateRMRPubPolicies(eps rtmgr.Endpoints) *[]string {
-       return generateRMRPolicies(eps, "00000           ")
+func (r *RmrPub) GeneratePolicies(eps rtmgr.Endpoints) *[]string {
+       rtmgr.Logger.Debug("Invoked rmr.GeneratePolicies, args: %v: ", eps)
+       return r.generateRMRPolicies(eps, "00000           ")
+}
+
+func (r *RmrPush) GeneratePolicies(eps rtmgr.Endpoints) *[]string {
+       rtmgr.Logger.Debug("Invoked rmr.GeneratePolicies, args: %v: ", eps)
+       return r.generateRMRPolicies(eps, "")
+}
+
+func (r *RmrPub) GetRouteTable(eps rtmgr.Endpoints) *rtmgr.RouteTable {
+       return r.getRouteTable(eps)
 }
 
 }
 
-func generateRMRPushPolicies(eps rtmgr.Endpoints) *[]string {
-       return generateRMRPolicies(eps, "")
+func (r *RmrPush) GetRouteTable(eps rtmgr.Endpoints) *rtmgr.RouteTable {
+       return r.getRouteTable(eps)
 }
 }
+
diff --git a/pkg/rpe/rmr_test.go b/pkg/rpe/rmr_test.go
new file mode 100644 (file)
index 0000000..bdbeff4
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+==================================================================================
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+       Mnemonic:       nngpub_test.go
+       Abstract:
+       Date:           25 April 2019
+*/
+package rpe
+
+import (
+       "routing-manager/pkg/rtmgr"
+       "routing-manager/pkg/stub"
+       "testing"
+)
+
+func resetTestDataset(testdata []rtmgr.Endpoint) {
+       rtmgr.Eps = make(map[string]*rtmgr.Endpoint)
+       for _, endpoint := range stub.ValidEndpoints {
+               ep := endpoint
+               rtmgr.Eps[ep.Uuid] = &ep
+       }
+}
+
+/*
+RmrPub.GeneratePolicies() method is tested for happy path case
+*/
+func TestRmrPubGeneratePolicies(t *testing.T) {
+       var rmrpub = RmrPub{}
+       resetTestDataset(stub.ValidEndpoints)
+
+       rawrt := rmrpub.GeneratePolicies(rtmgr.Eps)
+       t.Log(rawrt)
+}
+
+/*
+RmrPush.GeneratePolicies() method is tested for happy path case
+*/
+func TestRmrPushGeneratePolicies(t *testing.T) {
+       var rmrpush = RmrPush{}
+       resetTestDataset(stub.ValidEndpoints)
+
+       rawrt := rmrpush.GeneratePolicies(rtmgr.Eps)
+       t.Log(rawrt)
+}
index 636a439..5dd8f4d 100644 (file)
@@ -26,49 +26,39 @@ package rpe
 
 import (
        "errors"
 
 import (
        "errors"
-       "fmt"
-       "rtmgr"
+       "routing-manager/pkg/rtmgr"
+       "strconv"
 )
 
 var (
        SupportedRpes = []*RpeEngineConfig{
                &RpeEngineConfig{
 )
 
 var (
        SupportedRpes = []*RpeEngineConfig{
                &RpeEngineConfig{
-                       RpeEngine{
-                               Name:     "rmrpub",
-                               Version:  "pubsub",
-                               Protocol: "rmruta",
-                       },
-                       generatePolicies(generateRMRPubPolicies),
-                       true,
+                       Name:        "rmrpub",
+                       Version:     "pubsub",
+                       Protocol:    "rmruta",
+                       Instance:    NewRmrPub(),
+                       IsAvailable: true,
                },
                &RpeEngineConfig{
                },
                &RpeEngineConfig{
-                       RpeEngine{
-                               Name:     "rmrpush",
-                               Version:  "push",
-                               Protocol: "rmruta",
-                       },
-                       generatePolicies(generateRMRPushPolicies),
-                       true,
+                       Name:        "rmrpush",
+                       Version:     "pubsush",
+                       Protocol:    "rmruta",
+                       Instance:    NewRmrPush(),
+                       IsAvailable: true,
                },
        }
 )
 
                },
        }
 )
 
-func ListRpes() {
-       fmt.Printf("RPE:\n")
+func GetRpe(rpeName string) (RpeEngine, error) {
        for _, rpe := range SupportedRpes {
        for _, rpe := range SupportedRpes {
-               if rpe.IsAvailable {
-                       rtmgr.Logger.Info(rpe.Engine.Name + "/" + rpe.Engine.Version)
+               if rpe.Name == rpeName && rpe.IsAvailable {
+                       return rpe.Instance, nil
                }
        }
                }
        }
+       return nil, errors.New("SBI:" + rpeName + " is not supported or still not a available")
 }
 
 }
 
-func GetRpe(rpeName string) (*RpeEngineConfig, error) {
-       for _, rpe := range SupportedRpes {
-               if rpe.Engine.Name == rpeName && rpe.IsAvailable {
-                       return rpe, nil
-               }
-       }
-       return nil, errors.New("SBI:" + rpeName + " is not supported or still not a available")
+type Rpe struct {
 }
 
 /*
 }
 
 /*
@@ -77,7 +67,7 @@ Returns the Tx EndpointList map where the key is the messge type and also return
 Endpoint object's message type already transcoded to integer id
 */
 
 Endpoint object's message type already transcoded to integer id
 */
 
-func getRouteRxTxLists(eps rtmgr.Endpoints) (*map[string]rtmgr.EndpointList, *map[string]map[string]rtmgr.EndpointList) {
+func (r *Rpe) getRouteRxTxLists(eps rtmgr.Endpoints) (*map[string]rtmgr.EndpointList, *map[string]map[string]rtmgr.EndpointList) {
        txlist := make(map[string]rtmgr.EndpointList)
        rxgroups := make(map[string]map[string]rtmgr.EndpointList)
        for _, ep := range eps {
        txlist := make(map[string]rtmgr.EndpointList)
        rxgroups := make(map[string]map[string]rtmgr.EndpointList)
        for _, ep := range eps {
@@ -100,26 +90,144 @@ func getRouteRxTxLists(eps rtmgr.Endpoints) (*map[string]rtmgr.EndpointList, *ma
 Gets the raw xapp list and creates a route table for
 Returns the array of route table entries
 */
 Gets the raw xapp list and creates a route table for
 Returns the array of route table entries
 */
-func getRouteTable(eps rtmgr.Endpoints) *rtmgr.RouteTable {
-       tx, rx := getRouteRxTxLists(eps)
+func (r *Rpe) getRouteTable(eps rtmgr.Endpoints) *rtmgr.RouteTable {
+       tx, rx := r.getRouteRxTxLists(eps)
        var rt rtmgr.RouteTable
        for _, messagetype := range rtmgr.MESSAGETYPES {
        var rt rtmgr.RouteTable
        for _, messagetype := range rtmgr.MESSAGETYPES {
-               if _, ok := (*tx)[messagetype]; !ok {
+               /*if _, ok := (*tx)[messagetype]; !ok {
                        continue
                }
                if _, ok := (*rx)[messagetype]; !ok {
                        continue
                        continue
                }
                if _, ok := (*rx)[messagetype]; !ok {
                        continue
+               }*/
+               txList, ok := (*tx)[messagetype]
+               if !ok {
+                       txList = rtmgr.EndpointList{}
                }
                var rxgroups []rtmgr.EndpointList
                for _, endpointlist := range (*rx)[messagetype] {
                        rxgroups = append(rxgroups, endpointlist)
                }
                }
                var rxgroups []rtmgr.EndpointList
                for _, endpointlist := range (*rx)[messagetype] {
                        rxgroups = append(rxgroups, endpointlist)
                }
-               rte := rtmgr.RouteTableEntry{
-                       messagetype,
-                       (*tx)[messagetype],
-                       rxgroups,
+               if len(txList) > 0 || len(rxgroups) > 0 {
+                       rte := rtmgr.RouteTableEntry{
+                               messagetype,
+                               txList,
+                               rxgroups,
+                               -1,
+                       }
+                       rt = append(rt, rte)
                }
                }
-               rt = append(rt, rte)
        }
        }
+       r.addStaticRoutes(eps, &rt)
+       r.addSubscriptionRoutes(eps, &rt, &rtmgr.Subs)
        return &rt
 }
        return &rt
 }
+
+/*
+Adds specific static routes to the route table
+which cannot be calculated with endpoint tx/rx message types.
+*/
+func (r *Rpe) addStaticRoutes(eps rtmgr.Endpoints, rt *rtmgr.RouteTable) {
+       var uemanep, submanep *rtmgr.Endpoint
+       for _, ep := range eps {
+               if ep.Name == "UEMAN" {
+                       uemanep = ep
+               }
+               if ep.Name == "SUBMAN" {
+                       submanep = ep
+               }
+       }
+
+       if uemanep != nil && submanep != nil {
+               txlist := rtmgr.EndpointList{*uemanep}
+               rxlist := []rtmgr.EndpointList{[]rtmgr.Endpoint{*submanep}}
+               rte1 := rtmgr.RouteTableEntry{
+                       rtmgr.MESSAGETYPES["RIC_SUB_REQ"],
+                       txlist,
+                       rxlist,
+                       -1,
+               }
+               rte2 := rtmgr.RouteTableEntry{
+                       rtmgr.MESSAGETYPES["RIC_SUB_DEL_REQ"],
+                       txlist,
+                       rxlist,
+                       -1,
+               }
+               *rt = append(*rt, rte1)
+               *rt = append(*rt, rte2)
+       } else {
+               rtmgr.Logger.Warn("Cannot get the static route details of the platform components UEMAN/SUBMAN")
+       }
+}
+
+func getEndpointByName(eps *rtmgr.Endpoints, name string) *rtmgr.Endpoint {
+       for _, ep := range *eps {
+               if ep.Name == name {
+                       rtmgr.Logger.Debug("name: %s", ep.Name)
+                       rtmgr.Logger.Debug("ep: %v", ep)
+                       return ep
+               }
+       }
+       return nil
+}
+
+func getEndpointByUuid(eps *rtmgr.Endpoints, uuid string) *rtmgr.Endpoint {
+       for _, ep := range *eps {
+               if ep.Uuid == uuid {
+                       rtmgr.Logger.Debug("name: %s", ep.Uuid)
+                       rtmgr.Logger.Debug("ep: %v", ep)
+                       return ep
+               }
+       }
+       return nil
+}
+func (r *Rpe) addSubscriptionRoutes(eps rtmgr.Endpoints, rt *rtmgr.RouteTable, subs *rtmgr.SubscriptionList) {
+       rtmgr.Logger.Debug("rpe.addSubscriptionRoutes invoked")
+       rtmgr.Logger.Debug("params: %v", eps)
+       var e2termep, submanep, xappEp *rtmgr.Endpoint
+       var xappName string
+       e2termep = getEndpointByName(&eps, "E2TERM")
+       submanep = getEndpointByName(&eps, "SUBMAN")
+       if e2termep != nil && submanep != nil {
+               // looping through the subscription list, add routes one by one
+               for _, sub := range *subs {
+                       // SubMan -> XApp
+                       xappName = sub.Fqdn + ":" + strconv.Itoa(int(sub.Port))
+                       xappEp = getEndpointByUuid(&eps, xappName)
+                       if xappEp == nil {
+                               rtmgr.Logger.Error("XApp not found: %s", xappName)
+                               rtmgr.Logger.Debug("Endpoints: %v", eps)
+                       } else {
+                               txlist := rtmgr.EndpointList{*submanep}
+                               rxlist := []rtmgr.EndpointList{[]rtmgr.Endpoint{*xappEp}}
+                               subManMsgs := []string{"RIC_SUB_RESP", "RIC_SUB_FAILURE", "RIC_SUB_DEL_RESP", "RIC_SUB_DEL_FAILURE"}
+                               for _, entry := range subManMsgs {
+                                       rte := rtmgr.RouteTableEntry{
+                                               rtmgr.MESSAGETYPES[entry],
+                                               txlist,
+                                               rxlist,
+                                               sub.SubID,
+                                       }
+                                       *rt = append(*rt, rte)
+                               }
+                               // E2Term -> XApp
+                               txlist = rtmgr.EndpointList{*e2termep}
+                               rxlist = []rtmgr.EndpointList{[]rtmgr.Endpoint{*xappEp}}
+                               e2apMsgs := []string{"RIC_CONTROL_ACK", "RIC_CONTROL_FAILURE", "RIC_INDICATION"}
+                               for _, entry := range e2apMsgs {
+                                       rte := rtmgr.RouteTableEntry{
+                                               rtmgr.MESSAGETYPES[entry],
+                                               txlist,
+                                               rxlist,
+                                               sub.SubID,
+                                       }
+                                       *rt = append(*rt, rte)
+                               }
+                       }
+               }
+               rtmgr.Logger.Debug("addSubscriptionRoutes eps: %v", eps)
+       } else {
+               rtmgr.Logger.Warn("Subscription route update failure: Cannot get the static route details of the platform components E2TERM/SUBMAN")
+       }
+
+}
index b227c0e..426cc7c 100644 (file)
 
 package rpe
 
 
 package rpe
 
-import "rtmgr"
+import "routing-manager/pkg/rtmgr"
 
 type generatePolicies func(rtmgr.Endpoints) *[]string
 
 type generatePolicies func(rtmgr.Endpoints) *[]string
+type getRouteTable func(rtmgr.Endpoints) *rtmgr.RouteTable
 
 
-type RpeEngine struct {
-       Name     string
-       Version  string
-       Protocol string
+type RpeEngineConfig struct {
+       Name        string
+       Version     string
+       Protocol    string
+       Instance    RpeEngine
+       IsAvailable bool
 }
 
 }
 
-type RpeEngineConfig struct {
-       Engine           RpeEngine
-       GeneratePolicies generatePolicies
-       IsAvailable      bool
+type RpeEngine interface {
+       GeneratePolicies(rtmgr.Endpoints) *[]string
+       GetRouteTable(rtmgr.Endpoints) *rtmgr.RouteTable
 }
 }
index 9dd956e..5b27d76 100644 (file)
@@ -26,11 +26,17 @@ package rtmgr
 
 import (
        "github.com/jcelliott/lumber"
 
 import (
        "github.com/jcelliott/lumber"
+       "errors"
+       "strings"
+       "os"
+       "io/ioutil"
+       "encoding/json"
 )
 
 var (
        //TODO: temporary solution
        // CamelCase Message Types are for being able to test with old fashioned admin controll xApps
 )
 
 var (
        //TODO: temporary solution
        // CamelCase Message Types are for being able to test with old fashioned admin controll xApps
+       // TODO: Add a seperate message definition file (Not using the one from RMR to not create dependency on that library).
        MESSAGETYPES = map[string]string{
                "HandoverPreparation":              "0",
                "HandoverCancel":                   "1",
        MESSAGETYPES = map[string]string{
                "HandoverPreparation":              "0",
                "HandoverCancel":                   "1",
@@ -51,22 +57,98 @@ var (
                "RIC_E2_MANAGER_HC_RESPONSE":       "10008",
                "RIC_CONTROL_XAPP_CONFIG_REQUEST":  "100000",
                "RIC_CONTROL_XAPP_CONFIG_RESPONSE": "100001",
                "RIC_E2_MANAGER_HC_RESPONSE":       "10008",
                "RIC_CONTROL_XAPP_CONFIG_REQUEST":  "100000",
                "RIC_CONTROL_XAPP_CONFIG_RESPONSE": "100001",
+
+               "RIC_X2_SETUP_REQ":                 "10060",
+               "RIC_X2_SETUP_RESP":                "10061",
+               "RIC_X2_SETUP_FAILURE":             "10062",
+               "RIC_X2_RESET":                     "10070",
+               "RIC_X2_RESET_RESP":                "10071",
+
+               "RIC_SUB_REQ":                      "12010",
+               "RIC_SUB_RESP":                     "12011",
+               "RIC_SUB_FAILURE":                  "12012",
+               "RIC_SUB_DEL_REQ":                  "12020",
+               "RIC_SUB_DEL_RESP":                 "12021",
+               "RIC_SUB_DEL_FAILURE":              "12022",
+
+               "RIC_CONTROL_REQ":                  "12040",
+               "RIC_CONTROL_ACK":                  "12041",
+               "RIC_CONTROL_FAILURE":              "12042",
+               "RIC_INDICATION":                   "12050",
+               "RIC_ENDC_X2_SETUP_REQ":            "10360",
+               "RIC_ENDC_X2_SETUP_RESP":           "10361",
+               "RIC_ENDC_X2_SETUP_FAILURE":        "10362",
+               "RIC_ENDC_CONF_UPDATE":             "10370",
+               "RIC_ENDC_CONF_UPDATE_ACK":         "10371",
+               "RIC_ENDC_CONF_UPDATE_FAILURE":     "10372",
+               "RIC_RES_STATUS_REQ":               "10090",
+               "RIC_RES_STATUS_RESP":              "10091",
+               "RIC_RES_STATUS_FAILURE":           "10092",
+               "RIC_ENB_CONF_UPDATE":              "10080",
+               "RIC_ENB_CONF_UPDATE_ACK":          "10081",
+               "RIC_ENB_CONF_UPDATE_FAILURE":      "10082",
+               "RIC_ENB_LOAD_INFORMATION":         "10020",
+               "RIC_GNB_STATUS_INDICATION":        "10450",
+               "RIC_RESOURCE_STATUS_UPDATE":       "10100",
+               "RIC_ERROR_INDICATION":             "10030",
+               "DC_ADM_INT_CONTROL":               "20000",
+               "DC_ADM_INT_CONTROL_ACK":           "20001",
        }
        }
+
+       // Messagetype mappings for the platform components. 
+       // This implements static default routes needed by the RIC. Needs to be changed in case new components/message types needes to be added/updated.
+       // Representation : {"componentName1": {"tx": <tx message type list>, "rx": <rx message type list>}}
+       PLATFORMMESSAGETYPES = map[string]map[string][]string{
+               "E2TERM":   {"tx": []string{"RIC_X2_SETUP_REQ", "RIC_X2_SETUP_RESP", "RIC_X2_SETUP_FAILURE", "RIC_X2_RESET", "RIC_X2_RESET_RESP", "RIC_ENDC_X2_SETUP_REQ", "RIC_ENDC_X2_SETUP_RESP", "RIC_ENDC_X2_SETUP_FAILURE", "RIC_SUB_RESP", "RIC_SUB_FAILURE", "RIC_SUB_DEL_RESP", "RIC_SUB_DEL_FAILURE"}, "rx": []string{"RIC_X2_SETUP_REQ", "RIC_X2_SETUP_RESP", "RIC_X2_SETUP_FAILURE", "RIC_X2_RESET", "RIC_X2_RESET_RESP", "RIC_ENDC_X2_SETUP_REQ", "RIC_ENDC_X2_SETUP_RESP", "RIC_ENDC_X2_SETUP_FAILURE", "RIC_SUB_REQ", "RIC_SUB_DEL_REQ", "RIC_CONTROL_REQ"}},
+               "E2MAN":    {"tx": []string{"RIC_X2_SETUP_REQ", "RIC_X2_SETUP_RESP", "RIC_X2_SETUP_FAILURE", "RIC_X2_RESET", "RIC_X2_RESET_RESP", "RIC_ENDC_X2_SETUP_REQ", "RIC_ENDC_X2_SETUP_RESP", "RIC_ENDC_X2_SETUP_FAILURE"}, "rx": []string{"RIC_X2_SETUP_REQ", "RIC_X2_SETUP_RESP", "RIC_X2_SETUP_FAILURE", "RIC_X2_RESET", "RIC_X2_RESET_RESP", "RIC_ENDC_X2_SETUP_REQ", "RIC_ENDC_X2_SETUP_RESP", "RIC_ENDC_X2_SETUP_FAILURE"}},
+               "SUBMAN":   {"tx": []string{"RIC_SUB_REQ", "RIC_SUB_DEL_REQ"}, "rx": []string{"RIC_SUB_RESP", "RIC_SUB_FAILURE", "RIC_SUB_DEL_RESP", "RIC_SUB_DEL_FAILURE"}},
+               "UEMAN":    {"tx": []string{"RIC_CONTROL_REQ"}, "rx": []string{}},
+       }
+
        Logger = lumber.NewConsoleLogger(lumber.INFO)
        Logger = lumber.NewConsoleLogger(lumber.INFO)
-       Eps Endpoints
+       Eps    Endpoints
+       Subs   SubscriptionList
 )
 
 )
 
-func SetLogLevel(loglevel string) {
-       switch loglevel {
+func SetLogLevel(loglevel string) error{
+       switch strings.ToUpper(loglevel) {
        case "INFO":
                Logger.Level(lumber.INFO)
        case "INFO":
                Logger.Level(lumber.INFO)
+               return nil
        case "WARN":
                Logger.Level(lumber.WARN)
        case "WARN":
                Logger.Level(lumber.WARN)
+               return nil
        case "ERROR":
                Logger.Level(lumber.ERROR)
        case "ERROR":
                Logger.Level(lumber.ERROR)
+               return nil
        case "DEBUG":
                Logger.Info("debugmode")
                Logger.Level(lumber.DEBUG)
        case "DEBUG":
                Logger.Info("debugmode")
                Logger.Level(lumber.DEBUG)
+               return nil
+       default:
+               Logger.Error("Invalid log mode, setting info")
+               Logger.Level(lumber.INFO)
+               return errors.New("Invalid log level, setting info")
+       }
+}
+
+func GetPlatformComponents(configfile string) (*PlatformComponents, error) {
+       Logger.Debug("Invoked rtmgr.GetPlatformComponents("+ configfile +")")
+       var rcfg RtmgrConfig
+       jsonFile, err := os.Open(configfile)
+       if err != nil {
+               return nil, errors.New("cannot open the file due to: " + err.Error())
+       }
+       defer jsonFile.Close()
+       byteValue, err := ioutil.ReadAll(jsonFile)
+       if err != nil {
+               return nil, errors.New("cannot read the file due to: " + err.Error())
+       }
+       err = json.Unmarshal(byteValue, &rcfg)
+       if err != nil {
+               return nil, errors.New("cannot parse data due to: " + err.Error())
        }
        }
+       Logger.Debug("Platform components read from the configfile:  %v", rcfg.Pcs)
+       return &(rcfg.Pcs), nil
 }
 
 }
 
diff --git a/pkg/rtmgr/rtmgr_test.go b/pkg/rtmgr/rtmgr_test.go
new file mode 100644 (file)
index 0000000..ad6c504
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+==================================================================================
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+       Mnemonic:       rtmgr_test.go
+       Abstract:
+       Date:           14 May 2019
+*/
+
+package rtmgr
+
+import (
+       "testing"
+)
+
+func TestSetLogLevel(t *testing.T) {
+       modes_ok := []string{"info","warn","debug","error"}
+       modes_nok := []string{"inValId","LogLEVEL","PRoviDeD"}
+       for _, value := range(modes_ok) {
+               if SetLogLevel(value) != nil {
+                       t.Error("Invalid log level: " + value)
+               }
+       }
+
+        for _, value := range(modes_nok) {
+                if SetLogLevel(value) == nil {
+                        t.Error("Invalid log level: " + value)
+                }
+        }
+}
+
index bb84804..ba396c8 100644 (file)
@@ -33,6 +33,9 @@ type EndpointList []Endpoint
 
 type Endpoints map[string]*Endpoint
 
 
 type Endpoints map[string]*Endpoint
 
+type SubscriptionList []Subscription
+
+
 //TODO: uuid is not a real UUID but a string of "ip:port"
 // this should be changed to real UUID later on which should come from xApp Manager // petszila
 type Endpoint struct {
 //TODO: uuid is not a real UUID but a string of "ip:port"
 // this should be changed to real UUID later on which should come from xApp Manager // petszila
 type Endpoint struct {
@@ -52,6 +55,7 @@ type RouteTableEntry struct {
        MessageType string
        TxList      EndpointList
        RxGroups    []EndpointList
        MessageType string
        TxList      EndpointList
        RxGroups    []EndpointList
+       SubID       int16
 }
 
 type XApp struct {
 }
 
 type XApp struct {
@@ -69,3 +73,25 @@ type XAppInstance struct {
        TxMessages []string `json:"txMessages"`
        RxMessages []string `json:"rxMessages"`
 }
        TxMessages []string `json:"txMessages"`
        RxMessages []string `json:"rxMessages"`
 }
+
+type PlatformComponents []struct {
+       Name string `json:"name"`
+       Fqdn string `json:"fqdn"`
+       Port uint16 `json:"port"`
+}
+
+type RtmgrConfig struct {
+       Pcs PlatformComponents `json:"PlatformComponents"`
+}
+
+type RicComponents struct {
+       Xapps []XApp
+       Pcs   PlatformComponents
+}
+
+type Subscription struct {
+       SubID    int16
+       Fqdn     string
+       Port     uint16
+}
+
index c48a40f..ae96aa4 100644 (file)
@@ -17,7 +17,7 @@
 ==================================================================================
 */
 /*
 ==================================================================================
 */
 /*
-  Mnemonic:    nngpub.go
+  Mnemonic:    NngPub.go
   Abstract:    mangos (NNG) Pub/Sub SBI implementation
   Date:                12 March 2019
 */
   Abstract:    mangos (NNG) Pub/Sub SBI implementation
   Date:                12 March 2019
 */
@@ -26,52 +26,88 @@ package sbi
 
 import (
        "errors"
 
 import (
        "errors"
-       "nanomsg.org/go/mangos/v2"
        "nanomsg.org/go/mangos/v2/protocol/pub"
        _ "nanomsg.org/go/mangos/v2/transport/all"
        "nanomsg.org/go/mangos/v2/protocol/pub"
        _ "nanomsg.org/go/mangos/v2/transport/all"
-       "rtmgr"
+       "routing-manager/pkg/rtmgr"
        "strconv"
 )
 
        "strconv"
 )
 
-var socket mangos.Socket
+type NngPub struct {
+       Sbi
+       socket NngSocket
+       NewSocket CreateNewNngSocketHandler
+}
 
 
-func createNngPubEndpointSocket(ep *rtmgr.Endpoint) error {
-       return nil
+func NewNngPub() *NngPub {
+       instance := new(NngPub)
+       instance.NewSocket = createNewPubSocket
+       return instance
 }
 
 }
 
-func destroyNngPubEndpointSocket(ep *rtmgr.Endpoint) error {
-       return nil
+func createNewPubSocket() (NngSocket, error) {
+       rtmgr.Logger.Debug("Invoked createNewPubSocket()")
+       s, err := pub.NewSocket()
+       if err != nil {
+               return nil, errors.New("can't create new pub socket due to: " + err.Error())
+       }
+       return s, nil
 }
 
 }
 
-/*
-Creates the NNG publication channel
-*/
-func openNngPub(ip string) error {
+func (c *NngPub) Initialize(ip string) error {
+       rtmgr.Logger.Debug("Invoked sbi.Initialize("+ ip +")")
        var err error
        var err error
-       if socket, err = pub.NewSocket(); err != nil {
-               return errors.New("can't get new pub socket due to:" + err.Error())
+       c.socket, err = c.NewSocket()
+       if err != nil {
+               return errors.New("create socket error due to: " + err.Error())
+       }
+       if err = c.listen(ip); err != nil {
+               return errors.New("can't listen on socket due to: " + err.Error())
        }
        }
+       return nil
+}
+
+func (c *NngPub) Terminate() error {
+       rtmgr.Logger.Debug("Invoked sbi.Terminate()")
+       return c.closeSocket()
+}
+
+func (c *NngPub) AddEndpoint(ep *rtmgr.Endpoint) error {
+       return nil
+}
+
+func (c *NngPub) DeleteEndpoint(ep *rtmgr.Endpoint) error {
+       return nil
+}
+
+func (c *NngPub) UpdateEndpoints(rcs *rtmgr.RicComponents) {
+       c.updateEndpoints(rcs, c)
+}
+
+func (c *NngPub) listen(ip string) error {
+       rtmgr.Logger.Debug("Start listening on: " + ip)
        uri := DEFAULT_NNG_PUBSUB_SOCKET_PREFIX + ip + ":" + strconv.Itoa(DEFAULT_NNG_PUBSUB_SOCKET_NUMBER)
        rtmgr.Logger.Info("publishing on: " + uri)
        uri := DEFAULT_NNG_PUBSUB_SOCKET_PREFIX + ip + ":" + strconv.Itoa(DEFAULT_NNG_PUBSUB_SOCKET_NUMBER)
        rtmgr.Logger.Info("publishing on: " + uri)
-       if err = socket.Listen(uri); err != nil {
-               return errors.New("can't publish on socket " + uri + " due to:" + err.Error())
+       if err := c.socket.(NngSocket).Listen(uri); err != nil {
+               return errors.New("can't publish on socket " + uri + " due to: " + err.Error())
        }
        return nil
 }
 
        }
        return nil
 }
 
-func closeNngPub() error {
-       if err := socket.Close(); err != nil {
-               return errors.New("can't close socket due to:" + err.Error())
+func (c *NngPub) closeSocket() error {
+       rtmgr.Logger.Debug("Close NngPub Socket")
+       if err := c.socket.(NngSocket).Close(); err != nil {
+               return errors.New("can't close socket due to: " + err.Error())
        }
        return nil
 }
 
        }
        return nil
 }
 
-func publishAll(policies *[]string) error {
+func (c *NngPub) DistributeAll(policies *[]string) error {
+       rtmgr.Logger.Debug("Invoked: sbi.DistributeAll(), args: %v",(*policies))
        for _, pe := range *policies {
        for _, pe := range *policies {
-               if err := socket.Send([]byte(pe)); err != nil {
+               if err := c.socket.(NngSocket).Send([]byte(pe)); err != nil {
                        return errors.New("Unable to send policy entry due to: " + err.Error())
                }
        }
                        return errors.New("Unable to send policy entry due to: " + err.Error())
                }
        }
-       rtmgr.Logger.Info("NNG PUB: OK (# of Entries:" + strconv.Itoa(len((*policies))) + ")")
+       rtmgr.Logger.Info("NNG PUB: OK (# of Entries: " + strconv.Itoa(len((*policies))) + ")")
        return nil
 }
        return nil
 }
diff --git a/pkg/sbi/nngpub_test.go b/pkg/sbi/nngpub_test.go
new file mode 100644 (file)
index 0000000..85a300c
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+==================================================================================
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+       Mnemonic:       nngpub_test.go
+       Abstract:
+       Date:           25 April 2019
+*/
+package sbi
+
+import (
+       "errors"
+       "routing-manager/pkg/rtmgr"
+       "routing-manager/pkg/stub"
+       "testing"
+)
+
+/*
+Returns an error free Socket instance
+*/
+func createNewStubPubSocket() (NngSocket, error) {
+       socket := stub.MangosSocket{}
+       return socket, nil
+}
+
+/*
+Returns a SocketError
+*/
+func createNewStubPubSocketError() (NngSocket, error) {
+       return nil, errors.New("stub generated Create Socket error")
+}
+
+/*
+Returns a Socket which always generates error on Close()
+*/
+func createNewStubPubSocketCloseError() (NngSocket, error) {
+       socket := stub.MangosSocket{}
+       socket.GenerateSocketCloseError = true
+       return socket, nil
+}
+
+/*
+Returns a Socket which always generates error on Listen()
+*/
+func createNewStubPubSocketListenError() (NngSocket, error) {
+       socket := stub.MangosSocket{}
+       socket.GenerateSocketListenError = true
+       return socket, nil
+}
+
+/*
+Returns a Socket which always generates error on Send()
+*/
+func createNewStubPubSocketSendError() (NngSocket, error) {
+       socket := stub.MangosSocket{}
+       socket.GenerateSocketSendError = true
+       return socket, nil
+}
+
+/*
+Resets the EndpointList according to argumnets
+*/
+func resetTestPubDataset(instance NngPub, testdata []rtmgr.Endpoint) {
+       rtmgr.Eps = make(map[string]*rtmgr.Endpoint)
+       for _, endpoint := range testdata {
+               ep := endpoint
+               ep.Socket, _ = instance.NewSocket()
+               rtmgr.Eps[ep.Uuid] = &ep
+       }
+}
+
+/*
+nngPub.Initialize() method is tested for happy path case
+*/
+func TestNngPubInitialize(t *testing.T) {
+       var nngpub = NngPub{}
+       nngpub.NewSocket = createNewStubPubSocket
+
+       err := nngpub.Initialize("")
+       if err != nil {
+               t.Errorf("nngPub.Initialize() was incorrect, got: %v, want: %v.", err, nil)
+       }
+}
+
+/*
+nngPub.Initialize() is tested for Socket creating error case
+*/
+func TestNngPubInitializeWithSocketError(t *testing.T) {
+       var nngpub = NngPub{}
+       nngpub.NewSocket = createNewStubPubSocketError
+
+       err := nngpub.Initialize("")
+       if err == nil {
+               t.Errorf("nngPub.Initialize() was incorrect, got: %v, want: %v.", nil, "error")
+       }
+}
+
+/*
+nngPub.Initialize() is tested for Socket listening error case
+*/
+func TestNngPubInitializeWithSocketListenError(t *testing.T) {
+       var nngpub = NngPub{}
+       nngpub.NewSocket = createNewStubPubSocketListenError
+
+       err := nngpub.Initialize("")
+       if err == nil {
+               t.Errorf("nngPub.Initialize() was incorrect, got: %v, want: %v.", nil, "error")
+       }
+}
+
+/*
+nngPub.Terminate() method is empty, nothing to be tested
+*/
+func TestNngPubTerminate(t *testing.T) {
+       var nngpub = NngPub{}
+       nngpub.NewSocket = createNewStubPubSocket
+       nngpub.Initialize("")
+
+       err := nngpub.Terminate()
+       if err != nil {
+               t.Errorf("nngPub.Terminate() was incorrect, got: %v, want: %v.", err, nil)
+       }
+}
+
+/*
+nngPub.Terminate() is tested for Socket closing error case
+*/
+func TestNngPubTerminateWithSocketCloseError(t *testing.T) {
+       var nngpub = NngPub{}
+       nngpub.NewSocket = createNewStubPubSocketCloseError
+       nngpub.Initialize("")
+
+       err := nngpub.Terminate()
+       if err == nil {
+               t.Errorf("nngPub.Terminate() was incorrect, got: %v, want: %v.", nil, "error")
+       }
+}
+
+/*
+nngPub.UpdateEndpoints() is testd against stub.ValidXapps dataset
+*/
+func TestNngPubUpdateEndpoints(t *testing.T) {
+       var nngpub = NngPub{}
+       nngpub.NewSocket = createNewStubPubSocket
+       nngpub.Initialize("")
+       rtmgr.Eps = make(rtmgr.Endpoints)
+       nngpub.UpdateEndpoints(&stub.ValidRicComponents)
+       if rtmgr.Eps == nil {
+               t.Errorf("nngPub.UpdateEndpoints() result was incorrect, got: %v, want: %v.", nil, "rtmgr.Endpoints")
+       }
+}
+
+/*
+nngPub.AddEndpoint() method is empty, nothing to be tested
+*/
+func TestNngPubAddEndpoint(t *testing.T) {
+       var nngpub = NngPub{}
+       nngpub.NewSocket = createNewStubPubSocket
+
+       _ = nngpub.AddEndpoint(new(rtmgr.Endpoint))
+}
+
+/*
+nngPub.DeleteEndpoint() method is empty, nothing to be tested
+*/
+func TestNngPubDeleteEndpoint(t *testing.T) {
+       var nngpub = NngPub{}
+       nngpub.NewSocket = createNewStubPubSocket
+
+       _ = nngpub.DeleteEndpoint(new(rtmgr.Endpoint))
+}
+
+/*
+nngPub.DistributeAll() is tested for happy path case
+*/
+func TestNngPubDistributeAll(t *testing.T) {
+       var nngpub = NngPub{}
+       nngpub.NewSocket = createNewStubPubSocket
+       nngpub.Initialize("")
+       resetTestPubDataset(nngpub, stub.ValidEndpoints)
+
+       err := nngpub.DistributeAll(stub.ValidPolicies)
+       if err != nil {
+               t.Errorf("nngPub.DistributeAll(policies) was incorrect, got: %v, want: %v.", err, nil)
+       }
+}
+
+/*
+nngPub.DistributeAll() is tested for Sending error case
+*/
+func TestNngPubDistributeAllSocketSendError(t *testing.T) {
+       var nngpub = NngPub{}
+       nngpub.NewSocket = createNewStubPubSocketSendError
+       nngpub.Initialize("")
+       resetTestPubDataset(nngpub, stub.ValidEndpoints)
+
+       err := nngpub.DistributeAll(stub.ValidPolicies)
+       if err == nil {
+               t.Errorf("nngPub.DistributeAll(policies) was incorrect, got: %v, want: %v.", nil, "error")
+       }
+}
index 01bde0c..6f2535c 100644 (file)
@@ -29,87 +29,117 @@ import (
        "nanomsg.org/go/mangos/v2"
        "nanomsg.org/go/mangos/v2/protocol/push"
        _ "nanomsg.org/go/mangos/v2/transport/all"
        "nanomsg.org/go/mangos/v2"
        "nanomsg.org/go/mangos/v2/protocol/push"
        _ "nanomsg.org/go/mangos/v2/transport/all"
-       "rtmgr"
+       "routing-manager/pkg/rtmgr"
        "strconv"
 )
 
        "strconv"
 )
 
-func openNngPush(ip string) error {
-       return nil
+type NngPush struct {
+       Sbi
+       NewSocket CreateNewNngSocketHandler
 }
 
 }
 
-func closeNngPush() error {
-       return nil
+func NewNngPush() *NngPush {
+       instance := new(NngPush)
+       instance.NewSocket = createNewPushSocket
+       return instance
 }
 
 }
 
-func createNngPushEndpointSocket(ep *rtmgr.Endpoint) error {
-       rtmgr.Logger.Debug("Invoked sbi.createNngPushEndpointSocket")
-       rtmgr.Logger.Debug("args: %v", (*ep))
-       s, err := push.NewSocket()
+func createNewPushSocket() (NngSocket, error) {
+       rtmgr.Logger.Debug("Invoked: createNewPushSocket()")
+       socket, err := push.NewSocket()
        if err != nil {
        if err != nil {
-               return errors.New("can't open push socket for endpoint: " + ep.Name +" due to:" + err.Error())
+               return nil, errors.New("can't create new push socket due to:" + err.Error())
        }
        }
-       s.SetPipeEventHook(pipeEventHandler)
-       ep.Socket = s
-       dial(ep)
-       return nil
-}
-
-func destroyNngPushEndpointSocket(ep *rtmgr.Endpoint) error {
-       rtmgr.Logger.Debug("Invoked sbi.destroyNngPushEndpointSocket")
-       rtmgr.Logger.Debug("args: %v", (*ep))
-       if err:= ep.Socket.(mangos.Socket).Close(); err != nil {
-                       return errors.New("can't close push socket of endpoint:" + ep.Uuid + " due to:" + err.Error())
-               }
-       return nil
+       socket.SetPipeEventHook(pipeEventHandler)
+       return socket, nil
 }
 
 func pipeEventHandler(event mangos.PipeEvent, pipe mangos.Pipe) {
 }
 
 func pipeEventHandler(event mangos.PipeEvent, pipe mangos.Pipe) {
+       rtmgr.Logger.Debug("Invoked: pipeEventHandler()")
        for _, ep := range rtmgr.Eps {
                uri := DEFAULT_NNG_PIPELINE_SOCKET_PREFIX + ep.Ip + ":" + strconv.Itoa(DEFAULT_NNG_PIPELINE_SOCKET_NUMBER)
                if uri == pipe.Address() {
                        switch event {
                        case 1:
                                ep.IsReady = true
        for _, ep := range rtmgr.Eps {
                uri := DEFAULT_NNG_PIPELINE_SOCKET_PREFIX + ep.Ip + ":" + strconv.Itoa(DEFAULT_NNG_PIPELINE_SOCKET_NUMBER)
                if uri == pipe.Address() {
                        switch event {
                        case 1:
                                ep.IsReady = true
-                               rtmgr.Logger.Debug("Endpoint " + uri + " successfully registered")
+                               rtmgr.Logger.Debug("Endpoint " + uri + " successfully attached")
                        default:
                                ep.IsReady = false
                        default:
                                ep.IsReady = false
-                               rtmgr.Logger.Debug("Endpoint " + uri + " has been deregistered")
+                               rtmgr.Logger.Debug("Endpoint " + uri + " has been detached")
                        }
                        }
-               }       
+               }
+       }
+}
+
+func (c *NngPush) Initialize(ip string) error {
+       return nil
+}
+
+func (c *NngPush) Terminate() error {
+       return nil
+}
+
+func (c *NngPush) AddEndpoint(ep *rtmgr.Endpoint) error {
+       var err error
+       var socket NngSocket
+       rtmgr.Logger.Debug("Invoked sbi.AddEndpoint")
+       rtmgr.Logger.Debug("args: %v", (*ep))
+       socket, err = c.NewSocket()
+       if err != nil {
+               return errors.New("can't add new socket to endpoint:" + ep.Uuid + " due to: " + err.Error())
+       }
+       ep.Socket = socket
+       err = c.dial(ep)
+       if err != nil {
+               return errors.New("can't dial to endpoint:" + ep.Uuid + " due to: " + err.Error())
        }
        }
+       return nil
+}
+
+func (c *NngPush) DeleteEndpoint(ep *rtmgr.Endpoint) error {
+       rtmgr.Logger.Debug("Invoked sbi. DeleteEndpoint")
+       rtmgr.Logger.Debug("args: %v", (*ep))
+       if err:= ep.Socket.(NngSocket).Close(); err != nil {
+                       return errors.New("can't close push socket of endpoint:" + ep.Uuid + " due to: " + err.Error())
+               }
+       return nil
+}
+
+func (c *NngPush) UpdateEndpoints(rcs *rtmgr.RicComponents) {
+       c.updateEndpoints(rcs, c)
 }
 
 /*
 NOTE: Asynchronous dial starts a goroutine which keep maintains the connection to the given endpoint
 */
 }
 
 /*
 NOTE: Asynchronous dial starts a goroutine which keep maintains the connection to the given endpoint
 */
-func dial(ep *rtmgr.Endpoint) {
+func (c *NngPush) dial(ep *rtmgr.Endpoint) error {
        rtmgr.Logger.Debug("Dialing to endpoint: " + ep.Uuid)
        uri := DEFAULT_NNG_PIPELINE_SOCKET_PREFIX + ep.Ip + ":" + strconv.Itoa(DEFAULT_NNG_PIPELINE_SOCKET_NUMBER)
        options := make(map[string]interface{})
        options[mangos.OptionDialAsynch] = true
        rtmgr.Logger.Debug("Dialing to endpoint: " + ep.Uuid)
        uri := DEFAULT_NNG_PIPELINE_SOCKET_PREFIX + ep.Ip + ":" + strconv.Itoa(DEFAULT_NNG_PIPELINE_SOCKET_NUMBER)
        options := make(map[string]interface{})
        options[mangos.OptionDialAsynch] = true
-       if err := ep.Socket.(mangos.Socket).DialOptions(uri, options); err != nil {
-               rtmgr.Logger.Error("can't dial on push socket to " + uri + " due to:" + err.Error())
+       if err := ep.Socket.(NngSocket).DialOptions(uri, options); err != nil {
+               return errors.New("can't dial on push socket to " + uri + " due to: " + err.Error())
        }
        }
+       return nil
 }
 
 }
 
-func pushAll(policies *[]string) error {
-       rtmgr.Logger.Debug("Invoked: sbi.pushAll")
+func (c *NngPush) DistributeAll(policies *[]string) error {
+       rtmgr.Logger.Debug("Invoked: sbi.DistributeAll")
        rtmgr.Logger.Debug("args: %v", (*policies))
        for _, ep := range rtmgr.Eps {
                if ep.IsReady {
        rtmgr.Logger.Debug("args: %v", (*policies))
        for _, ep := range rtmgr.Eps {
                if ep.IsReady {
-                       go send(ep, policies)
+                       go c.send(ep, policies)
                } else {
                } else {
-                       rtmgr.Logger.Warn("Endpoint " + ep.Uuid + "is not ready")
+                       rtmgr.Logger.Warn("Endpoint " + ep.Uuid + " is not ready")
                }
        }
        return nil
 }
 
                }
        }
        return nil
 }
 
-func send(ep *rtmgr.Endpoint, policies *[]string) {
-       rtmgr.Logger.Debug("Invoked: sbi.pushAll")
+func (c *NngPush) send(ep *rtmgr.Endpoint, policies *[]string) {
        rtmgr.Logger.Debug("Push policy to endpoint: "+ ep.Uuid)
        for _, pe := range *policies {
        rtmgr.Logger.Debug("Push policy to endpoint: "+ ep.Uuid)
        for _, pe := range *policies {
-               if err := ep.Socket.(mangos.Socket).Send([]byte(pe)); err != nil {
+               if err := ep.Socket.(NngSocket).Send([]byte(pe)); err != nil {
                        rtmgr.Logger.Error("Unable to send policy entry due to: " + err.Error())
                }
        }
                        rtmgr.Logger.Error("Unable to send policy entry due to: " + err.Error())
                }
        }
diff --git a/pkg/sbi/nngpush_test.go b/pkg/sbi/nngpush_test.go
new file mode 100644 (file)
index 0000000..5e93169
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+==================================================================================
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+       Mnemonic:       nngpush_test.go
+       Abstract:
+       Date:           3 May 2019
+*/
+package sbi
+
+import (
+       "errors"
+       "routing-manager/pkg/rtmgr"
+       "routing-manager/pkg/stub"
+       "testing"
+)
+
+/*
+Returns an error free Socket instance
+*/
+func createNewStubPushSocket() (NngSocket, error) {
+       socket := stub.MangosSocket{}
+       return socket, nil
+}
+
+/*
+Returns a SocketError
+*/
+func createNewStubPushSocketError() (NngSocket, error) {
+       return nil, errors.New("stub generated Create Socket error")
+}
+
+/*
+Returns a Socket which always generates error on Close()
+*/
+func createNewStubPushSocketCloseError() (NngSocket, error) {
+       socket := stub.MangosSocket{}
+       socket.GenerateSocketCloseError = true
+       return socket, nil
+}
+
+/*
+Returns a Socket which always generates error on Send()
+*/
+func createNewStubPushSocketSendError() (NngSocket, error) {
+       socket := stub.MangosSocket{}
+       socket.GenerateSocketSendError = true
+       return socket, nil
+}
+
+/*
+Returns a Socket which always generates error on Dial()
+*/
+func createNewStubPushSocketDialError() (NngSocket, error) {
+       socket := stub.MangosSocket{}
+       socket.GenerateSocketDialError = true
+       return socket, nil
+}
+
+/*
+Resets the EndpointList according to argumnets
+*/
+func resetTestPushDataset(instance NngPush, testdata []rtmgr.Endpoint) {
+       rtmgr.Eps = make(map[string]*rtmgr.Endpoint)
+       for _, endpoint := range testdata {
+               ep := endpoint
+               ep.Socket, _ = instance.NewSocket()
+               rtmgr.Eps[ep.Uuid] = &ep
+       }
+}
+
+/*
+nngpush.Initialize() method is empty, nothing to be tested
+*/
+func TestNngPushInitialize(t *testing.T) {
+       var nngpush = NngPush{}
+       nngpush.NewSocket = createNewStubPushSocket
+
+       _ = nngpush.Initialize("")
+}
+
+/*
+nngpush.Terminate() method is empty, nothing to be tested
+*/
+func TestNngPushTerminate(t *testing.T) {
+       var nngpush = NngPush{}
+       nngpush.NewSocket = createNewStubPushSocket
+
+       _ = nngpush.Terminate()
+}
+
+/*
+nngpush.UpdateEndpoints() is testd against stub.ValidXapps dataset
+*/
+func TestNngPushUpdateEndpoints(t *testing.T) {
+       var nngpush = NngPush{}
+       nngpush.NewSocket = createNewStubPushSocket
+       rtmgr.Eps = make(rtmgr.Endpoints)
+
+       nngpush.UpdateEndpoints(&stub.ValidRicComponents)
+       if rtmgr.Eps == nil {
+               t.Errorf("nngpush.UpdateEndpoints() result was incorrect, got: %v, want: %v.", nil, "rtmgr.Endpoints")
+       }
+}
+
+/*
+nngpush.AddEndpoint() is tested for happy path case
+*/
+func TestNngPushAddEndpoint(t *testing.T) {
+       var err error
+       var nngpush = NngPush{}
+       nngpush.NewSocket = createNewStubPushSocket
+       resetTestPushDataset(nngpush, stub.ValidEndpoints)
+
+       err = nngpush.AddEndpoint(rtmgr.Eps["10.0.0.1:0"])
+       if err != nil {
+               t.Errorf("nngpush.AddEndpoint() return was incorrect, got: %v, want: %v.", err, "nil")
+       }
+       if rtmgr.Eps["10.0.0.1:0"].Socket == nil {
+               t.Errorf("nngpush.AddEndpoint() was incorrect, got: %v, want: %v.", nil, "Socket")
+       }
+}
+
+/*
+nngpush.AddEndpoint() is tested for Socket creating error case
+*/
+func TestNngPushAddEndpointWithSocketError(t *testing.T) {
+       var err error
+       var nngpush = NngPush{}
+       nngpush.NewSocket = createNewStubPushSocketError
+       resetTestPushDataset(nngpush, stub.ValidEndpoints)
+
+       err = nngpush.AddEndpoint(rtmgr.Eps["10.0.0.1:0"])
+       if err == nil {
+               t.Errorf("nngpush.AddEndpoint() was incorrect, got: %v, want: %v.", nil, "error")
+       }
+       if rtmgr.Eps["10.0.0.1:0"].Socket != nil {
+               t.Errorf("nngpush.AddEndpoint() was incorrect, got: %v, want: %v.", rtmgr.Eps["10.0.0.1:0"].Socket, nil)
+       }
+}
+
+/*
+nngpush.AddEndpoint() is tested for Dialing error case
+*/
+func TestNngPushAddEndpointWithSocketDialError(t *testing.T) {
+       var err error
+       var nngpush = NngPush{}
+       nngpush.NewSocket = createNewStubPushSocketDialError
+       resetTestPushDataset(nngpush, stub.ValidEndpoints)
+
+       err = nngpush.AddEndpoint(rtmgr.Eps["10.0.0.1:0"])
+       if err == nil {
+               t.Errorf("nngpush.AddEndpoint() was incorrect, got: %v, want: %v.", nil, "error")
+       }
+}
+
+/*
+nngpush.DistributeAll() is tested for happy path case
+*/
+func TestNngPushDistributeAll(t *testing.T) {
+       var err error
+       var nngpush = NngPush{}
+       nngpush.NewSocket = createNewStubPushSocket
+       resetTestPushDataset(nngpush, stub.ValidEndpoints)
+
+       err = nngpush.DistributeAll(stub.ValidPolicies)
+       if err != nil {
+               t.Errorf("nngpush.DistributeAll(policies) was incorrect, got: %v, want: %v.", err, "nil")
+       }
+}
+
+/*
+nngpush.DistributeAll() is tested for Sending error case
+*/
+func TestNngPushDistributeAllSocketSendError(t *testing.T) {
+       var err error
+       var nngpush = NngPush{}
+       nngpush.NewSocket = createNewStubPushSocketSendError
+       resetTestPushDataset(nngpush, stub.ValidEndpoints)
+
+       err = nngpush.DistributeAll(stub.ValidPolicies)
+       if err != nil {
+               t.Errorf("nngpush.DistributeAll(policies) was incorrect, got: %v, want: %v.", err, "nil")
+       }
+}
+
+func TestNngPushDeleteEndpoint(t *testing.T) {
+       var err error
+       var nngpush = NngPush{}
+       nngpush.NewSocket = createNewStubPushSocket
+       resetTestPushDataset(nngpush, stub.ValidEndpoints)
+
+       err = nngpush.DeleteEndpoint(rtmgr.Eps["10.0.0.1:0"])
+       if err != nil {
+               t.Errorf("nngpush.DeleteEndpoint() was incorrect, got: %v, want: %v.", err, "nil")
+       }
+}
+
+func TestNngPushDeleteEndpointWithSocketCloseError(t *testing.T) {
+       var err error
+       var nngpush = NngPush{}
+       nngpush.NewSocket = createNewStubPushSocketCloseError
+       resetTestPushDataset(nngpush, stub.ValidEndpoints)
+
+       err = nngpush.DeleteEndpoint(rtmgr.Eps["10.1.1.1:0"])
+       if err == nil {
+               t.Errorf("nngpush.DeleteEndpoint() was incorrect, got: %v, want: %v.", nil, "error")
+       }
+}
index 83b3790..09d9381 100644 (file)
@@ -27,69 +27,53 @@ package sbi
 
 import (
        "errors"
 
 import (
        "errors"
-       "fmt"
-       "rtmgr"
         "strconv"
         "strconv"
+       "routing-manager/pkg/rtmgr"
 )
 
 const DEFAULT_NNG_PUBSUB_SOCKET_PREFIX = "tcp://"
 const DEFAULT_NNG_PUBSUB_SOCKET_NUMBER = 4560
 const DEFAULT_NNG_PIPELINE_SOCKET_PREFIX = "tcp://"
 const DEFAULT_NNG_PIPELINE_SOCKET_NUMBER = 4561
 )
 
 const DEFAULT_NNG_PUBSUB_SOCKET_PREFIX = "tcp://"
 const DEFAULT_NNG_PUBSUB_SOCKET_NUMBER = 4560
 const DEFAULT_NNG_PIPELINE_SOCKET_PREFIX = "tcp://"
 const DEFAULT_NNG_PIPELINE_SOCKET_NUMBER = 4561
+const PLATFORMTYPE = "platformcomponenttype"
 
 var (
        SupportedSbis = []*SbiEngineConfig{
                &SbiEngineConfig{
 
 var (
        SupportedSbis = []*SbiEngineConfig{
                &SbiEngineConfig{
-                       SbiEngine{
-                               Name:     "nngpub",
-                               Version:  "v1",
-                               Protocol: "nngpubsub",
-                       },
-                       openSocket(openNngPub),
-                       closeSocket(closeNngPub),
-                       createEndpointSocket(createNngPubEndpointSocket),
-                       destroyEndpointSocket(createNngPubEndpointSocket),
-                       distributeAll(publishAll),
-                       true,
-               },
+                        Name:     "nngpush",
+                        Version:  "v1",
+                        Protocol: "nngpipeline",
+                        Instance: NewNngPush(),
+                        IsAvailable: true,
+                },
                &SbiEngineConfig{
                &SbiEngineConfig{
-                       SbiEngine{
-                               Name:     "nngpush",
-                               Version:  "v1",
-                               Protocol: "nngpipeline",
-                       },
-                       openSocket(openNngPush),
-                       closeSocket(closeNngPush),
-                       createEndpointSocket(createNngPushEndpointSocket),
-                       destroyEndpointSocket(destroyNngPushEndpointSocket),
-                       distributeAll(pushAll),
-                       true,
-               },
+                        Name:     "nngpub",
+                        Version:  "v1",
+                        Protocol: "nngpubsub",
+                        Instance: NewNngPub(),
+                        IsAvailable: true,
+                },
        }
 )
 
        }
 )
 
-func ListSbis() {
-       fmt.Printf("SBI:\n")
+func GetSbi(sbiName string) (SbiEngine, error) {
        for _, sbi := range SupportedSbis {
        for _, sbi := range SupportedSbis {
-               if sbi.IsAvailable {
-                       rtmgr.Logger.Info(sbi.Engine.Name + "/" + sbi.Engine.Version)
+               if sbi.Name == sbiName && sbi.IsAvailable {
+                       return sbi.Instance, nil
                }
        }
                }
        }
+       return nil, errors.New("SBI:" + sbiName + " is not supported or still not available")
 }
 
 }
 
-func GetSbi(sbiName string) (*SbiEngineConfig, error) {
-       for _, sbi := range SupportedSbis {
-               if (*sbi).Engine.Name == sbiName && (*sbi).IsAvailable {
-                       return sbi, nil
-               }
-       }
-       return nil, errors.New("SBI:" + sbiName + " is not supported or still not available")
+type Sbi struct {
+
 }
 
 }
 
-func pruneEndpointList(sbii *SbiEngineConfig) {
+func (s *Sbi) pruneEndpointList(sbii SbiEngine) {
         for _, ep := range rtmgr.Eps {
                 if !ep.Keepalive {
         for _, ep := range rtmgr.Eps {
                 if !ep.Keepalive {
-                       sbii.DestroyEndpointSocket(ep)
+                       rtmgr.Logger.Debug("deleting %v",ep)
+                       sbii.DeleteEndpoint(ep)
                         delete(rtmgr.Eps, ep.Uuid)
                 } else {
                         rtmgr.Eps[ep.Uuid].Keepalive = false
                         delete(rtmgr.Eps, ep.Uuid)
                 } else {
                         rtmgr.Eps[ep.Uuid].Keepalive = false
@@ -97,8 +81,8 @@ func pruneEndpointList(sbii *SbiEngineConfig) {
         }
 }
 
         }
 }
 
-func UpdateEndpointList(xapps *[]rtmgr.XApp, sbii *SbiEngineConfig) {
-        for _, xapp := range *xapps {
+func (s *Sbi) updateEndpoints(rcs *rtmgr.RicComponents, sbii SbiEngine) {
+       for _, xapp := range (*rcs).Xapps {
                 for _, instance := range xapp.Instances {
                         uuid := instance.Ip + ":" + strconv.Itoa(int(instance.Port))
                         if _, ok := rtmgr.Eps[uuid]; ok {
                 for _, instance := range xapp.Instances {
                         uuid := instance.Ip + ":" + strconv.Itoa(int(instance.Port))
                         if _, ok := rtmgr.Eps[uuid]; ok {
@@ -116,7 +100,7 @@ func UpdateEndpointList(xapps *[]rtmgr.XApp, sbii *SbiEngineConfig) {
                                         false,
                                         true,
                                 }
                                         false,
                                         true,
                                 }
-                                if err := sbii.CreateEndpointSocket(ep); err != nil {
+                                if err := sbii.AddEndpoint(ep); err != nil {
                                         rtmgr.Logger.Error("can't create socket for endpoint: " + ep.Name + " due to:" + err.Error())
                                         continue
                                 }
                                         rtmgr.Logger.Error("can't create socket for endpoint: " + ep.Name + " due to:" + err.Error())
                                         continue
                                 }
@@ -124,5 +108,36 @@ func UpdateEndpointList(xapps *[]rtmgr.XApp, sbii *SbiEngineConfig) {
                         }
                 }
         }
                         }
                 }
         }
-        pruneEndpointList(sbii)
+       s.updatePlatformEndpoints(&((*rcs).Pcs), sbii)
+        s.pruneEndpointList(sbii)
+}
+
+func (s *Sbi ) updatePlatformEndpoints(pcs *rtmgr.PlatformComponents, sbii SbiEngine) {
+       rtmgr.Logger.Debug("updatePlatformEndpoints invoked. PCS: %v", *pcs)
+        for _, pc := range *pcs {
+                uuid := pc.Fqdn + ":" + strconv.Itoa(int(pc.Port))
+                if _, ok := rtmgr.Eps[uuid]; ok {
+                        rtmgr.Eps[uuid].Keepalive = true
+                } else {
+                        ep := &rtmgr.Endpoint{
+                                uuid,
+                                pc.Name,
+                                PLATFORMTYPE,
+                                pc.Fqdn,
+                                pc.Port,
+                                rtmgr.PLATFORMMESSAGETYPES[pc.Name]["tx"],
+                                rtmgr.PLATFORMMESSAGETYPES[pc.Name]["rx"],
+                                nil,
+                                false,
+                                true,
+                        }
+                       rtmgr.Logger.Debug("ep created: %v",ep)
+                        if err := sbii.AddEndpoint(ep); err != nil {
+                                rtmgr.Logger.Error("can't create socket for endpoint: " + ep.Name + " due to:" + err.Error())
+                                continue
+                        }
+                        rtmgr.Eps[uuid] = ep
+                }
+        }
 }
 }
+
diff --git a/pkg/sbi/sbi_test.go b/pkg/sbi/sbi_test.go
new file mode 100644 (file)
index 0000000..5c7e848
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+==================================================================================
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+       Mnemonic:       sbi_test.go
+       Abstract:
+       Date:           25 April 2019
+*/
+package sbi
+
+import (
+       "testing"
+       "reflect"
+       "errors"
+)
+
+func TestGetSbi(t *testing.T) {
+       var errtype = errors.New("")
+       var sbitype = new(NngPub)
+       var invalids = []string{"nngpus", ""}
+
+       sbii, err := GetSbi("nngpub")
+       if err != nil {
+               t.Errorf("GetSbi(nngpub) was incorrect, got: %v, want: %v.", reflect.TypeOf(err), nil)
+       }
+       if reflect.TypeOf(sbii) != reflect.TypeOf(sbitype) {
+               t.Errorf("GetSbi(nngpub) was incorrect, got: %v, want: %v.", reflect.TypeOf(sbii), reflect.TypeOf(sbitype))
+       }
+
+       for _, arg := range invalids {
+               _, err := GetSbi(arg)
+               if err == nil {
+                       t.Errorf("GetSbi("+arg+") was incorrect, got: %v, want: %v.", reflect.TypeOf(err), reflect.TypeOf(errtype))
+               }
+       }
+}
index f971ff5..357d87c 100644 (file)
 
 package sbi
 
 
 package sbi
 
-import "rtmgr"
+import "routing-manager/pkg/rtmgr"
 
 
-type distributeAll func(*[]string) error
-type openSocket func(string) error
-type closeSocket func() error
-type createEndpointSocket func(*rtmgr.Endpoint) error
-type destroyEndpointSocket func(*rtmgr.Endpoint) error
-
-
-type SbiEngine struct {
+type SbiEngineConfig struct {
        Name     string
        Version  string
        Name     string
        Version  string
-       Protocol string
+  Protocol string
+  Instance SbiEngine
+  IsAvailable bool
 }
 
 }
 
-type SbiEngineConfig struct {
-       Engine        SbiEngine
-       OpenSocket    openSocket
-       CloseSocket   closeSocket
-       CreateEndpointSocket createEndpointSocket
-       DestroyEndpointSocket destroyEndpointSocket
-       DistributeAll distributeAll
-       IsAvailable   bool
+type SbiEngine interface {
+  Initialize(string) error
+  Terminate() error
+  DistributeAll(*[]string) error
+  AddEndpoint(*rtmgr.Endpoint) error
+  DeleteEndpoint(*rtmgr.Endpoint) error
+  UpdateEndpoints(*rtmgr.RicComponents)
 }
 }
+
+type NngSocket interface {
+       Listen(string) error
+       Send([]byte) error
+  Close() error
+  DialOptions(string, map[string]interface{}) error
+}
+
+type CreateNewNngSocketHandler func() (NngSocket,error)
index 11c3350..638f1af 100644 (file)
@@ -29,7 +29,7 @@ import (
        "errors"
        "io/ioutil"
        "os"
        "errors"
        "io/ioutil"
        "os"
-       "rtmgr"
+       "routing-manager/pkg/rtmgr"
 )
 
 /*
 )
 
 /*
@@ -37,10 +37,19 @@ Reads the content of the rt.json file
 Parses the JSON content and loads each xApp entry into an xApp object
 Returns an array os xApp object
 */
 Parses the JSON content and loads each xApp entry into an xApp object
 Returns an array os xApp object
 */
-func fileReadAll(file string) (*[]rtmgr.XApp, error) {
-       rtmgr.Logger.Debug("Invoked file.fileReadAll")
-       rtmgr.Logger.Debug("file.fileReadAll opens file: " + file)
-       var xapps *[]rtmgr.XApp
+
+type File struct {
+       Sdl
+}
+
+func NewFile() *File {
+       instance := new(File)
+       return instance
+}
+
+func (f *File) ReadAll(file string) (*rtmgr.RicComponents, error) {
+       rtmgr.Logger.Debug("Invoked sdl.ReadAll("+ file +")")
+       var rcs *rtmgr.RicComponents
        jsonFile, err := os.Open(file)
        if err != nil {
                return nil, errors.New("cannot open the file due to: " + err.Error())
        jsonFile, err := os.Open(file)
        if err != nil {
                return nil, errors.New("cannot open the file due to: " + err.Error())
@@ -50,19 +59,43 @@ func fileReadAll(file string) (*[]rtmgr.XApp, error) {
        if err != nil {
                return nil, errors.New("cannot read the file due to: " + err.Error())
        }
        if err != nil {
                return nil, errors.New("cannot read the file due to: " + err.Error())
        }
-       err = json.Unmarshal(byteValue, &xapps)
+       err = json.Unmarshal(byteValue, &rcs)
        if err != nil {
                return nil, errors.New("cannot parse data due to: " + err.Error())
        }
        if err != nil {
                return nil, errors.New("cannot parse data due to: " + err.Error())
        }
-       rtmgr.Logger.Debug("file.fileReadAll returns: %v", xapps)
-       return xapps, nil
+       rtmgr.Logger.Debug("file.fileReadAll returns: %v", rcs)
+       return rcs, nil
 }
 
 }
 
-func fileWriteAll(file string, xapps *[]rtmgr.XApp) error {
-       rtmgr.Logger.Debug("Invoked file.fileWriteAll")
+func (f *File) WriteAll(file string, rcs *rtmgr.RicComponents) error {
+       rtmgr.Logger.Debug("Invoked sdl.WriteAll")
        rtmgr.Logger.Debug("file.fileWriteAll writes into file: " + file)
        rtmgr.Logger.Debug("file.fileWriteAll writes into file: " + file)
-       rtmgr.Logger.Debug("file.fileWriteAll writes data: %v", (*xapps))
-       byteValue, err := json.Marshal(xapps)
+       rtmgr.Logger.Debug("file.fileWriteAll writes data: %v", (*rcs))
+       byteValue, err := json.Marshal(rcs)
+       if err != nil {
+               return errors.New("cannot convert data due to: " + err.Error())
+       }
+       err = ioutil.WriteFile(file, byteValue, 0644)
+       if err != nil {
+               return errors.New("cannot write file due to: " + err.Error())
+       }
+       return nil
+}
+
+func (f *File) WriteXapps(file string, xapps *[]rtmgr.XApp) error {
+       rtmgr.Logger.Debug("Invoked sdl.WriteXapps")
+       rtmgr.Logger.Debug("file.fileWriteXapps writes into file: " + file)
+       rtmgr.Logger.Debug("file.fileWriteXapps writes data: %v", (*xapps))
+
+       ricData, err := NewFile().ReadAll(file)
+       if err != nil || ricData == nil {
+               rtmgr.Logger.Error("cannot get data from sdl interface due to: " + err.Error())
+               return errors.New("cannot read full ric data to modify xapps data, due to:  " + err.Error())
+       }
+
+       ricData.Xapps = *xapps
+
+       byteValue, err := json.Marshal(ricData)
        if err != nil {
                return errors.New("cannot convert data due to: " + err.Error())
        }
        if err != nil {
                return errors.New("cannot convert data due to: " + err.Error())
        }
index 198b05a..b6e0bde 100644 (file)
@@ -26,49 +26,36 @@ package sdl
 
 import (
        "errors"
 
 import (
        "errors"
-       "fmt"
-       "rtmgr"
 )
 
 var (
        SupportedSdls = []*SdlEngineConfig{
                &SdlEngineConfig{
 )
 
 var (
        SupportedSdls = []*SdlEngineConfig{
                &SdlEngineConfig{
-                       SdlEngine{
-                               Name:     "file",
-                               Version:  "v1",
-                               Protocol: "rawfile",
-                       },
-                       readAll(fileReadAll),
-                       writeAll(fileWriteAll),
-                       true,
+                       Name:     "file",
+                       Version:  "v1",
+                       Protocol: "rawfile",
+                       Instance: NewFile(),
+                       IsAvailable: true,
                },
                &SdlEngineConfig{
                },
                &SdlEngineConfig{
-                       SdlEngine{
-                               Name:     "redis",
-                               Version:  "v1",
-                               Protocol: "nsdl",
-                       },
-                       readAll(nil),
-                       writeAll(nil),
-                       false,
+                       Name:     "redis",
+                       Version:  "v1",
+                       Protocol: "ndsl",
+                       Instance: nil,
+                       IsAvailable: false,
                },
        }
 )
 
                },
        }
 )
 
-func ListSdls() {
-       fmt.Printf("SDL:\n")
+func GetSdl(sdlName string) (SdlEngine, error) {
        for _, sdl := range SupportedSdls {
        for _, sdl := range SupportedSdls {
-               if sdl.IsAvailable {
-                       rtmgr.Logger.Info(sdl.Engine.Name + "/" + sdl.Engine.Version)
+               if sdl.Name == sdlName && sdl.IsAvailable {
+                       return sdl.Instance, nil
                }
        }
                }
        }
+       return nil, errors.New("SDL:" + sdlName + " is not supported or still not a available")
 }
 
 }
 
-func GetSdl(sdlName string) (*SdlEngineConfig, error) {
-       for _, sdl := range SupportedSdls {
-               if sdl.Engine.Name == sdlName && sdl.IsAvailable {
-                       return sdl, nil
-               }
-       }
-       return nil, errors.New("SDL:" + sdlName + " is not supported or still not a available")
+type Sdl struct {
+
 }
 }
diff --git a/pkg/sdl/sdl_test.go b/pkg/sdl/sdl_test.go
new file mode 100644 (file)
index 0000000..8dcf7c0
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+==================================================================================
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+       Mnemonic:       nngpub_test.go
+       Abstract:
+       Date:           25 April 2019
+*/
+package sdl
+
+import (
+       "routing-manager/pkg/stub"
+       "testing"
+)
+
+/*
+RmrPub.GeneratePolicies() method is tested for happy path case
+*/
+func TestFileWriteAll(t *testing.T) {
+       var err error
+       var file = File{}
+
+       err = file.WriteAll("ut.rt", &stub.ValidRicComponents)
+       t.Log(err)
+}
+
+/*
+RmrPush.GeneratePolicies() method is tested for happy path case
+*/
+func TestFileReadAll(t *testing.T) {
+       var err error
+       var file = File{}
+
+       data, err := file.ReadAll("ut.rt")
+       t.Log(data)
+       t.Log(err)
+}
index 961c88e..dd86890 100644 (file)
 */
 package sdl
 
 */
 package sdl
 
-import "rtmgr"
+import "routing-manager/pkg/rtmgr"
 
 
-type readAll func(string) (*[]rtmgr.XApp, error)
-type writeAll func(string, *[]rtmgr.XApp) error
+type readAll func(string) (*rtmgr.RicComponents, error)
+type writeAll func(string, *rtmgr.RicComponents) error
 
 
-type SdlEngine struct {
+type SdlEngineConfig struct {
        Name     string
        Version  string
        Name     string
        Version  string
-       Protocol string
+  Protocol string
+  Instance SdlEngine
+       IsAvailable bool
 }
 
 }
 
-type SdlEngineConfig struct {
-       Engine      SdlEngine
-       ReadAll     readAll
-       WriteAll    writeAll
-       IsAvailable bool
+type SdlEngine interface {
+  ReadAll(string) (*rtmgr.RicComponents, error)
+  WriteAll(string, *rtmgr.RicComponents) error
+  WriteXapps(string, *[]rtmgr.XApp) error
 }
 }
diff --git a/pkg/stub/mangos.go b/pkg/stub/mangos.go
new file mode 100644 (file)
index 0000000..0620648
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+==================================================================================
+  Copyright (c) 2019 AT&T Intellectual Property.
+  Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+  Mnemonic:    mangos.go
+  Abstract:    
+  Date:                3 May 2019
+*/
+
+package stub
+
+import "errors"
+
+type MangosMessage struct {
+       Header []byte
+       Body []byte
+       Pipe MangosPipe
+       bbuf  []byte
+       hbuf  []byte
+       bsize int
+       pool  interface {}
+}
+
+type MangosProtocolInfo struct {
+       Self     uint16
+       Peer     uint16
+       SelfName string
+       PeerName string
+}
+
+// Mangos Listener Stub
+
+type MangosListener struct {
+
+}
+
+func (l MangosListener) Listen() error {
+       return nil
+}
+
+func (l MangosListener) Close() error {
+       return nil
+}
+
+func (l MangosListener) Address() string {
+       return ""
+}
+
+func (l MangosListener) SetOption(s string, i interface{}) error {
+       return nil
+}
+
+func (l MangosListener) GetOption(s string) (interface{},error) {
+       return nil, nil
+}
+
+// Mangos Dialer Stub
+
+type MangosDialer struct {
+       }
+
+func (d MangosDialer) Open() error {
+       return nil
+}
+
+func (d MangosDialer) Close() error {
+       return nil
+}
+
+func (d MangosDialer) Address() string {
+       return ""
+}
+
+func (d MangosDialer) SetOption(s string, i interface{}) error {
+       return nil
+}
+
+func (d MangosDialer) GetOption(s string) (interface{},error) {
+       return nil, nil
+}
+
+// Mangos Context Stub
+
+type MangosContext struct {
+
+}
+
+func (c MangosContext) Close() error {
+       return nil
+}
+
+func (c MangosContext) SetOption(s string, i interface{}) error {
+       return nil
+}
+
+func (c MangosContext) GetOption(s string) (interface{},error) {
+       return nil, nil
+}
+
+func (c MangosContext) Send(b []byte) error {
+       return nil
+}
+
+func (c MangosContext) Recv() ([]byte, error) {
+       return make([]byte,0), nil
+}
+
+func (c MangosContext) SendMsg(*MangosMessage) error {
+       return nil
+}
+
+func (c MangosContext) RecvMsg() (*MangosMessage, error) {
+       return nil, nil
+}
+
+// Mangos Pipe Stub
+
+type MangosPipe struct {
+
+}
+
+func (p MangosPipe) ID() uint32 {
+       return 0
+}
+
+func (p MangosPipe) Listener() MangosListener {
+       return MangosListener{}
+}
+
+func (p MangosPipe) Dialer() MangosDialer {
+       return MangosDialer{}
+}
+
+func (p MangosPipe) Close() error {
+       return nil
+}
+
+func (p MangosPipe) Address() string {
+       return ""
+}
+
+func (p MangosPipe) GetOption(s string) (interface{},error) {
+       return nil, nil
+}
+
+// Mangos PipeEventHook Stub
+
+type PipeEventHook func(int, MangosPipe)
+
+// Mangos Socket Stub
+
+type MangosSocket struct {
+       GenerateSocketCloseError bool
+       GenerateSocketSendError bool
+       GenerateSocketDialError bool
+       GenerateSocketListenError bool
+}
+
+func (s MangosSocket) Info() MangosProtocolInfo {
+       return MangosProtocolInfo{}
+}
+
+func (s MangosSocket) Close() error {
+       if s.GenerateSocketCloseError {
+               return errors.New("stub generated Socket Close error")
+       }
+       return nil
+}
+
+func (s MangosSocket) Send(b []byte) error {
+       if s.GenerateSocketSendError {
+               return errors.New("stub generated Socket Send error")
+       }
+       return nil
+}
+
+func (s MangosSocket) Recv() ([]byte, error) {
+       return make([]byte,0), nil
+}
+
+func (s MangosSocket) SendMsg(*MangosMessage) error {
+       return nil
+}
+
+func (s MangosSocket) RecvMsg() (*MangosMessage, error) {
+       return nil, nil
+}
+
+func (s MangosSocket) Dial(t string) error {
+       if s.GenerateSocketDialError {
+               return errors.New("stub generated Socket Dial error")
+       }
+       return nil
+}
+
+func (s MangosSocket) DialOptions(t string, m map[string]interface{}) error {
+       if err := s.Dial(t); err != nil {
+               return err
+       }
+       return nil
+}
+
+func (s MangosSocket) NewDialer(t string, m map[string]interface{}) (MangosDialer, error) {
+       return MangosDialer{}, nil
+}
+
+func (s MangosSocket) Listen(t string) error {
+       if s.GenerateSocketListenError {
+               return errors.New("stub generated Socket Listen error")
+       }
+       return nil
+}
+
+func (s MangosSocket) ListenOptions(t string, m map[string]interface{}) error {
+       return nil
+}
+
+func (s MangosSocket) NewListener(t string, m map[string]interface{}) (MangosListener, error) {
+       return MangosListener{}, nil
+}
+
+func (s MangosSocket) SetOption(t string, i interface{}) error {
+       return nil
+}
+
+func (s MangosSocket) GetOption(t string) (interface{},error) {
+       return nil, nil
+}
+
+func (s MangosSocket) OpenContext() (MangosContext, error) {
+       return MangosContext{}, nil
+}
+
+func (s MangosSocket) SetPipeEventHook(p PipeEventHook) PipeEventHook {
+       return nil
+}
+
+// Mangos ProtocolPipe Stub
+
+type MangosProtocolPipe struct {
+
+}
+
+func (p MangosProtocolPipe) ID() uint32 {
+       return 0
+}
+
+func (p MangosProtocolPipe) Close() error {
+       return nil
+}
+
+func (p MangosProtocolPipe) SendMsg(m *MangosMessage) error {
+       return nil
+}
+
+func (p MangosProtocolPipe) RecvMsg() *MangosMessage {
+       return nil
+}
+
+// Mangos ProtocolContext Stub
+
+type MangosProtocolContext struct {
+
+}
+
+func (p MangosProtocolContext) Close() error {
+       return nil
+}
+
+func (p MangosProtocolContext) SendMsg(m *MangosMessage) error {
+       return nil
+}
+
+func (p MangosProtocolContext) RecvMsg() (*MangosMessage, error) {
+       return nil, nil
+}
+
+func (p MangosProtocolContext) GetOption(s string) (interface{}, error) {
+       return nil, nil
+}
+
+func (p MangosProtocolContext) SetOption(s string, i interface{}) error {
+       return nil
+}
+
+// Mangos ProtocolBase Stub
+
+type MangosProtocolBase struct {
+       MangosProtocolContext
+}
+
+func (p MangosProtocolBase) Info() MangosProtocolInfo {
+       return MangosProtocolInfo{}
+}
+
+func (p MangosProtocolBase) AddPipe(t MangosProtocolPipe) error {
+       return nil
+}
+
+func (p MangosProtocolBase) RemovePipe(MangosProtocolPipe) {
+
+}
+
+func (p MangosProtocolBase) OpenContext() (MangosProtocolContext, error) {
+       return MangosProtocolContext{}, nil
+}
diff --git a/pkg/stub/stub.go b/pkg/stub/stub.go
new file mode 100644 (file)
index 0000000..9ab7d1d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+==================================================================================
+  Copyright (c) 2019 AT&T Intellectual Property.
+  Copyright (c) 2019 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+/*
+  Mnemonic:    stub.go
+  Abstract:
+  Date:                27 April 2019
+*/
+
+package stub
+
+import "routing-manager/pkg/rtmgr"
+
+var ValidXapps = &[]rtmgr.XApp{
+       rtmgr.XApp{Name: "app1", Status: "", Version: "", Instances: []rtmgr.XAppInstance{rtmgr.XAppInstance{Name: "instance1", Status: "unknown", Ip: "10.0.0.1", Port: 0, TxMessages: []string{"HandoverPreparation", "HandoverCancel"}, RxMessages: []string{"HandoverPreparation", "HandoverCancel"}}}},
+       rtmgr.XApp{Name: "app2", Status: "", Version: "", Instances: []rtmgr.XAppInstance{rtmgr.XAppInstance{Name: "instance2", Status: "unknown", Ip: "192.168.0.1", Port: 0, TxMessages: []string{"HandoverCancel", "HandoverPreparation"}, RxMessages: []string{"HandoverPreparation", "HandoverCancel"}}}},
+       rtmgr.XApp{Name: "app3", Status: "", Version: "", Instances: []rtmgr.XAppInstance{rtmgr.XAppInstance{Name: "instance2", Status: "unknown", Ip: "10.1.1.1", Port: 0, TxMessages: []string{"X2Setup"}, RxMessages: []string{"Reset", "UEContextRelease"}}}},
+       rtmgr.XApp{Name: "app4", Status: "", Version: "", Instances: []rtmgr.XAppInstance{rtmgr.XAppInstance{Name: "instance2", Status: "unknown", Ip: "10.2.2.1", Port: 0, TxMessages: []string{"Reset", "UEContextRelease"}, RxMessages: []string{"", ""}}}},
+}
+
+var ValidPlatformComponents = &rtmgr.PlatformComponents {
+       {Name:"E2TERM", Fqdn:"e2term", Port:4561},
+       {Name:"SUBMAN", Fqdn:"subman", Port:4561},
+       {Name:"E2MAN",  Fqdn:"e2man",  Port:4561},
+       {Name:"UEMAN",  Fqdn:"ueman",  Port:4561},
+}
+
+var ValidEndpoints = []rtmgr.Endpoint{
+       rtmgr.Endpoint{Uuid: "10.0.0.1:0", Name: "i1", XAppType: "app1", Ip: "", Port: 0, TxMessages: []string{"", ""}, RxMessages: []string{"", ""}, Socket: nil, IsReady: true, Keepalive: true},
+       rtmgr.Endpoint{Uuid: "192.168.0.1:0", Name: "i2", XAppType: "app2", Ip: "", Port: 0, TxMessages: []string{"", ""}, RxMessages: []string{"", ""}, Socket: nil, IsReady: false, Keepalive: false},
+       rtmgr.Endpoint{Uuid: "10.1.1.1:0", Name: "i3", XAppType: "app3", Ip: "", Port: 0, TxMessages: []string{"", ""}, RxMessages: []string{"", ""}, Socket: nil, IsReady: true, Keepalive: false},
+       rtmgr.Endpoint{Uuid: "10.2.2.1:0", Name: "i4", XAppType: "app4", Ip: "", Port: 0, TxMessages: []string{"", ""}, RxMessages: []string{"", ""}, Socket: nil, IsReady: false, Keepalive: true},
+}
+
+var ValidRicComponents = rtmgr.RicComponents {
+       *ValidXapps, *ValidPlatformComponents,
+}
+
+var ValidPolicies = &[]string{"", ""}
old mode 100755 (executable)
new mode 100644 (file)
similarity index 86%
rename from build/container/run_rtmgr.sh
rename to run_rtmgr.sh
index f098eb5..7976b6c
@@ -22,4 +22,4 @@
 #      Abstract:       Runs the rtmgr executable with proper arguments
 #      Date:           19 March 2019
 #
 #      Abstract:       Runs the rtmgr executable with proper arguments
 #      Date:           19 March 2019
 #
-exec ./rtmgr -xm-url=$XMURL -sbi=$SBI -sbi-if=$IP -filename=$RTFILE -rpe=$RPE -loglevel=INFO
+exec ./rtmgr  -xm-url=$XMURL -nbi=$NBI -nbi-if=$NBIURL -sbi=$SBI -sbi-if=$SBIURL -filename=$RTFILE -rpe=$RPE -loglevel=$LOGLEVEL -configfile=$CFGFILE 
diff --git a/test/data/platform_routes.json b/test/data/platform_routes.json
new file mode 100644 (file)
index 0000000..d53fe85
--- /dev/null
@@ -0,0 +1,26 @@
+{
+    "PlatformComponents":
+    [
+        {
+            "name": "E2TERM",
+            "fqdn": "e2term",
+            "port": 4561
+        },
+        {
+            "name": "SUBMAN",
+            "fqdn": "subman",
+            "port": 4562
+        },
+        {
+            "name": "E2MAN",
+            "fqdn": "e2man",
+            "port": 4563
+        },
+        {
+            "name": "UEMAN",
+            "fqdn": "ueman",
+            "port": 4564
+        }
+    ]
+}
+
diff --git a/test/data/xapps.json b/test/data/xapps.json
new file mode 100644 (file)
index 0000000..49db5c5
--- /dev/null
@@ -0,0 +1,45 @@
+{
+  "id": 1,
+  "event": "whatever",
+  "data-version": 0,
+  "data":
+  "[{
+    \"name\": \"xapp-01\",
+    \"status\": \"unknown\",
+    \"version\": \"1.2.3\",
+    \"instances\": [{
+      \"name\": \"xapp-01-instance-01\",
+      \"status\": \"pending\",
+      \"ip\": \"10.244.0.51\",
+      \"port\": 4560,
+      \"txMessages\": [\"ControlIndication\", \"HandoverPreparation\"],
+      \"rxMessages\": [\"LoadIndication\", \"Reset\"]
+    },{
+      \"name\": \"xapp-01-instance-02\",
+      \"status\": \"pending\",
+      \"ip\": \"10.244.0.52\",
+      \"port\": 4560,
+      \"txMessages\": [\"ControlIndication\", \"HandoverPreparation\"],
+      \"rxMessages\": [\"LoadIndication\", \"Reset\"]
+    }]
+  },{
+    \"name\": \"xapp-02\",
+    \"status\": \"unknown\",
+    \"version\": \"1.2.3\",
+    \"instances\": [{
+      \"name\": \"xapp-02-instance-01\",
+      \"status\": \"pending\",
+      \"ip\": \"10.244.0.53\",
+      \"port\": 4560,
+      \"txMessages\": [\"ControlIndication\", \"HandoverPreparation\"],
+      \"rxMessages\": [\"LoadIndication\", \"Reset\"]
+    },{
+      \"name\": \"xapp-02-instance-01\",
+      \"status\": \"pending\",
+      \"ip\": \"10.244.0.54\",
+      \"port\": 4560,
+      \"txMessages\": [\"ControlIndication\", \"HandoverPreparation\"],
+      \"rxMessages\": [\"LoadIndication\", \"Reset\"]
+    }]
+  }]"
+}
\ No newline at end of file
index ac8d2b9..8856f84 100644 (file)
@@ -22,4 +22,6 @@
 #
 FROM node
 
 #
 FROM node
 
+COPY middleware.js middleware.js
+
 RUN npm install -g json-server
 RUN npm install -g json-server
diff --git a/test/docker/xmgr.build/middleware.js b/test/docker/xmgr.build/middleware.js
new file mode 100644 (file)
index 0000000..217fb4d
--- /dev/null
@@ -0,0 +1,10 @@
+module.exports = function (req, res, next) {
+  if (req.method === 'POST') {
+    // Converts POST to GET and move payload to query params
+    // This way it will make JSON Server that it's GET request
+    req.method = 'GET'
+    req.query = req.body
+  }
+  // Continue to JSON Server router
+  next()
+}
index ea02211..ae104b3 100644 (file)
@@ -41,12 +41,12 @@ spec:
         args:
         - /run_test-tx.sh
         ports:
         args:
         - /run_test-tx.sh
         ports:
-        - containerPort: 4555
+        - containerPort: 4561
         env:
         - name: NAME
           value: "RM"
         - name: PORT
         env:
         - name: NAME
           value: "RM"
         - name: PORT
-          value: "tcp:4555"
+          value: "tcp:4561"
         - name: RATE
           value: "10"
         - name: RMR_RTG_SVC
         - name: RATE
           value: "10"
         - name: RMR_RTG_SVC
index a12c824..caac0e8 100644 (file)
@@ -29,73 +29,79 @@ data:
   xmgrdata: |
     { 
     "xapps":
   xmgrdata: |
     { 
     "xapps":
-        [{
-            "name": "admin",
-            "status": "unknown",
-            "version": "1.2.3",
-            "instances": [{
-                    "name": "admin-01",
-                    "status": "pending",
-                    "ip": "10.244.1.19",
-                    "port": 4561,
-                    "txMessages": ["HandoverPreparation","HandoverCancel"],
-                    "rxMessages": []
-                },
-                {
-                    "name": "admin-02",
-                    "status": "pending",
-                    "ip": "10.244.3.16",
-                    "port": 4555,
-                    "txMessages": ["HandoverPreparation","HandoverCancel"],
-                    "rxMessages": []
-                }
-            ]
-        },
+        [
+            {
+                "name": "admin",
+                "status": "unknown",
+                "version": "1.2.3",
+                "instances": [{
+                        "name": "admin-01",
+                        "status": "pending",
+                        "ip": "10.244.1.19",
+                        "port": 4561,
+                        "txMessages": ["HandoverPreparation","HandoverCancel"],
+                        "rxMessages": []
+                    },
+                    {
+                        "name": "admin-02",
+                        "status": "pending",
+                        "ip": "10.244.3.16",
+                        "port": 4555,
+                        "txMessages": ["HandoverPreparation","HandoverCancel"],
+                        "rxMessages": []
+                    }
+                ]
+            },
+            {
+                "name": "xapp",
+                "status": "unknown",
+                "version": "1.2.3",
+                "instances": [{
+                        "name": "xapp-01",
+                        "status": "pending",
+                        "ip": "192.168.2.1",
+                        "port": 32300,
+                        "txMessages": ["X2Setup","Reset"],
+                        "rxMessages": ["HandoverPreparation","HandoverCancel"]
+                    },
+                    {
+                        "name": "xapp-02",
+                        "status": "pending",
+                        "ip": "192.168.2.2",
+                        "port": 32300,
+                        "txMessages": ["X2Setup","Reset"],
+                        "rxMessages": ["HandoverPreparation","HandoverCancel"]
+                    }
+                ]
+            },
+            {
+                "name": "e2t",
+                "status": "unknown",
+                "version": "1.2.3",
+                "instances": [{
+                        "name": "e2t-01",
+                        "status": "pending",
+                        "ip": "192.168.3.1",
+                        "port": 32300,
+                        "txMessages": [],
+                        "rxMessages": ["HandoverPreparation","HandoverCancel","X2Setup","Reset"]
+                    },
+                    {
+                        "name": "e2t-02",
+                        "status": "pending",
+                        "ip": "192.168.3.2",
+                        "port": 32300,
+                        "txMessages": [],
+                        "rxMessages": ["HandoverPreparation","HandoverCancel","X2Setup","Reset"]
+                    }
+                ]
+            }
+    ],
+    "subscriptions":
         {
         {
-            "name": "xapp",
-            "status": "unknown",
-            "version": "1.2.3",
-            "instances": [{
-                    "name": "xapp-01",
-                    "status": "pending",
-                    "ip": "192.168.2.1",
-                    "port": 32300,
-                    "txMessages": ["X2Setup","Reset"],
-                    "rxMessages": ["HandoverPreparation","HandoverCancel"]
-                },
-                {
-                    "name": "xapp-02",
-                    "status": "pending",
-                    "ip": "192.168.2.2",
-                    "port": 32300,
-                    "txMessages": ["X2Setup","Reset"],
-                    "rxMessages": ["HandoverPreparation","HandoverCancel"]
-                }
-            ]
-        },
-        {
-            "name": "e2t",
-            "status": "unknown",
-            "version": "1.2.3",
-            "instances": [{
-                    "name": "e2t-01",
-                    "status": "pending",
-                    "ip": "192.168.3.1",
-                    "port": 32300,
-                    "txMessages": [],
-                    "rxMessages": ["HandoverPreparation","HandoverCancel","X2Setup","Reset"]
-                },
-                {
-                    "name": "e2t-02",
-                    "status": "pending",
-                    "ip": "192.168.3.2",
-                    "port": 32300,
-                    "txMessages": [],
-                    "rxMessages": ["HandoverPreparation","HandoverCancel","X2Setup","Reset"]
-                }
-            ]
+            "id": "1ILBltYYzEGzWRrVPZKmuUmhwcc",
+            "version": 0,
+            "eventType": "all"
         }
         }
-
-        ]
     }
 
     }
 
index 768bae7..b7aeeee 100644 (file)
@@ -37,12 +37,13 @@ spec:
     spec:
       containers:
       - name: xmgr
     spec:
       containers:
       - name: xmgr
-        image: cmaster:5000/xmgr:0.0.2
+        image: xmgr:mock
         args:
         - json-server
         - -w
         - --host=0.0.0.0
         - /db/xapps.json
         args:
         - json-server
         - -w
         - --host=0.0.0.0
         - /db/xapps.json
+        - --middlewares=middleware.js
         ports:
         - containerPort: 3000
         volumeMounts:
         ports:
         - containerPort: 3000
         volumeMounts: