From 12ec4c639a5b2fefd9aebeb281ba0e8d824b1b47 Mon Sep 17 00:00:00 2001 From: elinuxhenrik Date: Fri, 10 Dec 2021 16:52:42 +0100 Subject: [PATCH] Add ICS simulator to Franthaul consumer Issue-ID: NONRTRIC-664 Signed-off-by: elinuxhenrik Change-Id: I8ad34fd58c2502d586d7b320c3cf40261b2cbe9f --- .../oruclosedlooprecovery/goversion/.gitignore | 1 + .../oruclosedlooprecovery/goversion/README.md | 16 +++-- .../oruclosedlooprecovery/goversion/go.mod | 5 +- .../oruclosedlooprecovery/goversion/main.go | 18 +++--- .../oruclosedlooprecovery/goversion/main_test.go | 6 +- .../goversion/stub/ics/ics.go | 70 ++++++++++++++++++++++ .../goversion/stub/producer/producerstub.go | 49 ++++++++++++++- 7 files changed, 140 insertions(+), 25 deletions(-) create mode 100644 test/usecases/oruclosedlooprecovery/goversion/stub/ics/ics.go diff --git a/test/usecases/oruclosedlooprecovery/goversion/.gitignore b/test/usecases/oruclosedlooprecovery/goversion/.gitignore index 381bc416..fcf8128c 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/.gitignore +++ b/test/usecases/oruclosedlooprecovery/goversion/.gitignore @@ -4,3 +4,4 @@ oruclosedloop producer sdnr +ics diff --git a/test/usecases/oruclosedlooprecovery/goversion/README.md b/test/usecases/oruclosedlooprecovery/goversion/README.md index ec542c12..b5b93553 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/README.md +++ b/test/usecases/oruclosedlooprecovery/goversion/README.md @@ -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 diff --git a/test/usecases/oruclosedlooprecovery/goversion/go.mod b/test/usecases/oruclosedlooprecovery/goversion/go.mod index 2eaa371c..4bfef684 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/go.mod +++ b/test/usecases/oruclosedlooprecovery/goversion/go.mod @@ -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 ) diff --git a/test/usecases/oruclosedlooprecovery/goversion/main.go b/test/usecases/oruclosedlooprecovery/goversion/main.go index b7d68954..4bf4ec63 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/main.go +++ b/test/usecases/oruclosedlooprecovery/goversion/main.go @@ -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) } } diff --git a/test/usecases/oruclosedlooprecovery/goversion/main_test.go b/test/usecases/oruclosedlooprecovery/goversion/main_test.go index 3fcb23ea..6b1b0e51 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/main_test.go +++ b/test/usecases/oruclosedlooprecovery/goversion/main_test.go @@ -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 index 00000000..c2d9e73f --- /dev/null +++ b/test/usecases/oruclosedlooprecovery/goversion/stub/ics/ics.go @@ -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) + } + } + +} diff --git a/test/usecases/oruclosedlooprecovery/goversion/stub/producer/producerstub.go b/test/usecases/oruclosedlooprecovery/goversion/stub/producer/producerstub.go index 78462ba2..4af16cf5 100644 --- a/test/usecases/oruclosedlooprecovery/goversion/stub/producer/producerstub.go +++ b/test/usecases/oruclosedlooprecovery/goversion/stub/producer/producerstub.go @@ -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) } - } -- 2.16.6