Add ICS simulator to Franthaul consumer 95/7295/1
authorelinuxhenrik <henrik.b.andersson@est.tech>
Fri, 10 Dec 2021 15:52:42 +0000 (16:52 +0100)
committerelinuxhenrik <henrik.b.andersson@est.tech>
Fri, 10 Dec 2021 15:52:46 +0000 (16:52 +0100)
Issue-ID: NONRTRIC-664
Signed-off-by: elinuxhenrik <henrik.b.andersson@est.tech>
Change-Id: I8ad34fd58c2502d586d7b320c3cf40261b2cbe9f

test/usecases/oruclosedlooprecovery/goversion/.gitignore
test/usecases/oruclosedlooprecovery/goversion/README.md
test/usecases/oruclosedlooprecovery/goversion/go.mod
test/usecases/oruclosedlooprecovery/goversion/main.go
test/usecases/oruclosedlooprecovery/goversion/main_test.go
test/usecases/oruclosedlooprecovery/goversion/stub/ics/ics.go [new file with mode: 0644]
test/usecases/oruclosedlooprecovery/goversion/stub/producer/producerstub.go

index ec542c1..b5b9355 100644 (file)
@@ -23,9 +23,9 @@ The configured public key and cerificate shall be PEM-encoded. A self signed cer
 
     openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650
 
-T## Functionality
+## Functionality
 
-he creation of the job is not done when the consumer is started. Instead the consumer provides a REST API where it can be started and stopped, described below.
+The creation of the job is not done when the consumer is started. Instead the consumer provides a REST API where it can be started and stopped, described below.
 
 >- /start  Creates the job in ICS.
 >- /stop   Deletes the job in ICS.
@@ -34,14 +34,20 @@ If the consumer is shut down with a SIGTERM, it will also delete the job before
 
 ## Development
 
-To make it easy to test during development of the consumer, two stubs are provided in the `stub` folder.
+To make it easy to test during development of the consumer, three stubs are provided in the `stub` folder.
 
-One, under the `producer` folder, called `producer` that stubs the producer and pushes an array with one message with `eventSeverity` alternating between `NORMAL` and `CRITICAL`. To build and start the stub, do the following:
+A producer stub, under the `producer` folder, that stubs the producer and pushes an array with one message with `eventSeverity` alternating between `NORMAL` and `CRITICAL`. The stub does not start to send messages until it recieves a create job call from the ICS stub. When a delete job call comes from the ICS stub it stops sending messages. To build and start the stub, do the following:
 >1. cd stub/producer
 >2. go build
 >3. ./producer
 
-One, under the `sdnr` folder, called `sdnr` that at startup will listen for REST calls and print the body of them. By default, it listens to the port `3904`, but his can be overridden by passing a `-port [PORT]` flag when starting the stub. To build and start the stub, do the following:
+An ICS stub, under the `ics` folder, that listens for create and delete job calls from the consumer. When it gets a call it calls the producer stub with the correct create or delete call and the provided job ID. By default, it listens to the port `8083`, but his can be overridden by passing a `-port [PORT]` flag when starting the stub. To build and start the stub, do the following:
+>1. cd stub/ics
+>2. go build
+>3. ./ics
+
+
+An SNDR stub, under the `sdnr` folder, that at startup will listen for REST calls and print the body of them. By default, it listens to the port `3904`, but his can be overridden by passing a `-port [PORT]` flag when starting the stub. To build and start the stub, do the following:
 >1. cd stub/sdnr
 >2. go build
 >3. ./sdnr
index 2eaa371..4bfef68 100644 (file)
@@ -5,6 +5,7 @@ go 1.17
 require (
        github.com/sirupsen/logrus v1.8.1
        github.com/stretchr/testify v1.7.0
+       github.com/hashicorp/go-retryablehttp v0.7.0
 )
 
 require (
@@ -14,9 +15,5 @@ require (
        github.com/stretchr/objx v0.1.1 // indirect
        golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
        gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
-)
-
-require (
        github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
-       github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
 )
index b7d6895..4bf4ec6 100644 (file)
@@ -37,20 +37,16 @@ import (
        "oransc.org/usecase/oruclosedloop/internal/restclient"
 )
 
-type Server interface {
-       ListenAndServe() error
-}
-
 const jobId = "14e7bb84-a44d-44c1-90b7-6995a92ad43c"
 
 var jobRegistrationInfo = struct {
-       InfoTypeId    string      `json:"info_type_id"`
-       JobResultUri  string      `json:"job_result_uri"`
+       InfoTypeID    string      `json:"info_type_id"`
+       JobResultURI  string      `json:"job_result_uri"`
        JobOwner      string      `json:"job_owner"`
        JobDefinition interface{} `json:"job_definition"`
 }{
-       InfoTypeId:    "STD_Fault_Messages",
-       JobResultUri:  "",
+       InfoTypeID:    "STD_Fault_Messages",
+       JobResultURI:  "",
        JobOwner:      "O-RU Closed Loop Usecase",
        JobDefinition: "{}",
 }
@@ -72,7 +68,7 @@ func doInit() {
        log.Debug("Using configuration: ", configuration)
 
        consumerPort = fmt.Sprint(configuration.ConsumerPort)
-       jobRegistrationInfo.JobResultUri = configuration.ConsumerHost + ":" + consumerPort
+       jobRegistrationInfo.JobResultURI = configuration.ConsumerHost + ":" + consumerPort
 
        linkfailureConfig = linkfailure.Configuration{
                SDNRAddress:  configuration.SDNRAddress,
@@ -150,7 +146,7 @@ func startServer() {
        if err != nil {
                log.Errorf("Server stopped unintentionally due to: %v. Deleteing job.", err)
                if deleteErr := deleteJob(); deleteErr != nil {
-                       log.Error(fmt.Sprintf("Unable to delete consumer job due to: %v. Please remove job %v manually.", deleteErr, jobId))
+                       log.Errorf("Unable to delete consumer job due to: %v. Please remove job %v manually.", deleteErr, jobId)
                }
        }
 }
@@ -185,7 +181,7 @@ func deleteOnShutdown(s chan os.Signal) {
        <-s
        log.Info("Shutting down gracefully.")
        if err := deleteJob(); err != nil {
-               log.Error(fmt.Sprintf("Unable to delete job on shutdown due to: %v. Please remove job %v manually.", err, jobId))
+               log.Errorf("Unable to delete job on shutdown due to: %v. Please remove job %v manually.", err, jobId)
        }
 }
 
index 3fcb23e..6b1b0e5 100644 (file)
@@ -68,7 +68,7 @@ func Test_init(t *testing.T) {
        assertions.Equal(wantedConfiguration, configuration)
 
        assertions.Equal(fmt.Sprint(wantedConfiguration.ConsumerPort), consumerPort)
-       assertions.Equal(wantedConfiguration.ConsumerHost+":"+fmt.Sprint(wantedConfiguration.ConsumerPort), jobRegistrationInfo.JobResultUri)
+       assertions.Equal(wantedConfiguration.ConsumerHost+":"+fmt.Sprint(wantedConfiguration.ConsumerPort), jobRegistrationInfo.JobResultURI)
 
        wantedLinkFailureConfig := linkfailure.Configuration{
                SDNRAddress:  wantedConfiguration.SDNRAddress,
@@ -194,7 +194,7 @@ func Test_getRouter_shouldContainAllPathsWithHandlers(t *testing.T) {
 func Test_startHandler(t *testing.T) {
        assertions := require.New(t)
 
-       jobRegistrationInfo.JobResultUri = "host:80"
+       jobRegistrationInfo.JobResultURI = "host:80"
 
        type args struct {
                mockReturnBody   []byte
@@ -271,7 +271,7 @@ func Test_startHandler(t *testing.T) {
 func Test_stopHandler(t *testing.T) {
        assertions := require.New(t)
 
-       jobRegistrationInfo.JobResultUri = "host:80"
+       jobRegistrationInfo.JobResultURI = "host:80"
 
        type args struct {
                mockReturnBody   []byte
diff --git a/test/usecases/oruclosedlooprecovery/goversion/stub/ics/ics.go b/test/usecases/oruclosedlooprecovery/goversion/stub/ics/ics.go
new file mode 100644 (file)
index 0000000..c2d9e73
--- /dev/null
@@ -0,0 +1,70 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2021: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package main
+
+import (
+       "flag"
+       "fmt"
+       "net/http"
+       "time"
+
+       "github.com/gorilla/mux"
+)
+
+var client = &http.Client{
+       Timeout: 5 * time.Second,
+}
+
+func main() {
+       port := flag.Int("port", 8083, "The port this consumer will listen on")
+       flag.Parse()
+       fmt.Println("Starting SDNR stub on port ", *port)
+
+       r := mux.NewRouter()
+       r.HandleFunc("/data-consumer/v1/info-jobs/{jobId}", handleCalls).Methods(http.MethodPut, http.MethodDelete)
+       fmt.Println(http.ListenAndServe(fmt.Sprintf(":%v", *port), r))
+}
+
+func handleCalls(w http.ResponseWriter, r *http.Request) {
+       vars := mux.Vars(r)
+       id, ok := vars["jobId"]
+       if ok {
+               fmt.Println(r.Method, " of job ", id)
+               if r.Method == http.MethodPut {
+                       req, _ := http.NewRequest(http.MethodPut, "http://localhost:8085/create/"+id, nil)
+                       r, err := client.Do(req)
+                       if err != nil {
+                               fmt.Println("Failed to create job in producer ", err)
+                               return
+                       }
+                       fmt.Println("Created job in producer ", r.Status)
+               } else {
+                       req, _ := http.NewRequest(http.MethodDelete, "http://localhost:8085/delete/"+id, nil)
+                       r, err := client.Do(req)
+                       if err != nil {
+                               fmt.Println("Failed to delete job in producer ", err)
+                               return
+                       }
+                       fmt.Println("Deleted job in producer ", r.Status)
+               }
+       }
+
+}
index 78462ba..4af16cf 100644 (file)
@@ -23,13 +23,51 @@ package main
 import (
        "bytes"
        "encoding/json"
+       "fmt"
        "net/http"
        "time"
 
+       "github.com/gorilla/mux"
        "oransc.org/usecase/oruclosedloop/internal/ves"
 )
 
+var started bool
+
 func main() {
+       r := mux.NewRouter()
+       r.HandleFunc("/create/{jobId}", createJobHandler).Methods(http.MethodPut)
+       r.HandleFunc("/delete/{jobId}", deleteJobHandler).Methods(http.MethodDelete)
+
+       fmt.Println("Listening on port 8085")
+       fmt.Println(http.ListenAndServe(":8085", r))
+}
+
+func createJobHandler(w http.ResponseWriter, r *http.Request) {
+       vars := mux.Vars(r)
+       id, ok := vars["jobId"]
+       if !ok {
+               http.Error(w, "No job ID provided", http.StatusBadRequest)
+               return
+       }
+
+       started = true
+       fmt.Println("Start pushing messages for job: ", id)
+       startPushingMessages()
+}
+
+func deleteJobHandler(w http.ResponseWriter, r *http.Request) {
+       vars := mux.Vars(r)
+       id, ok := vars["jobId"]
+       if !ok {
+               http.Error(w, "No job ID provided", http.StatusBadRequest)
+               return
+       }
+
+       fmt.Println("Stop pushing messages for job: ", id)
+       started = false
+}
+
+func startPushingMessages() {
        message := ves.FaultMessage{
                Event: ves.Event{
                        CommonEventHeader: ves.CommonEventHeader{
@@ -41,12 +79,16 @@ func main() {
                        },
                },
        }
+
        client := &http.Client{
                Timeout: 5 * time.Second,
        }
 
        critical := true
        for range time.Tick(2 * time.Second) {
+               if !started {
+                       break
+               }
                if critical {
                        message.Event.FaultFields.EventSeverity = "CRITICAL"
                        critical = false
@@ -60,7 +102,10 @@ func main() {
                req, _ := http.NewRequest(http.MethodPost, "http://localhost:40935", bytes.NewBuffer(msgToSend))
                req.Header.Set("Content-Type", "application/json; charset=utf-8")
 
-               client.Do(req)
+               r, err := client.Do(req)
+               if err != nil {
+                       fmt.Println("Error sending to consumer: ", err)
+               }
+               fmt.Printf("Sent %v message to consumer. Got response %v\n", message.Event.FaultFields.EventSeverity, r.Status)
        }
-
 }