oruclosedloop
producer
sdnr
+ics
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.
## 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
require (
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
+ github.com/hashicorp/go-retryablehttp v0.7.0
)
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
)
"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: "{}",
}
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,
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)
}
}
}
<-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)
}
}
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,
func Test_startHandler(t *testing.T) {
assertions := require.New(t)
- jobRegistrationInfo.JobResultUri = "host:80"
+ jobRegistrationInfo.JobResultURI = "host:80"
type args struct {
mockReturnBody []byte
func Test_stopHandler(t *testing.T) {
assertions := require.New(t)
- jobRegistrationInfo.JobResultUri = "host:80"
+ jobRegistrationInfo.JobResultURI = "host:80"
type args struct {
mockReturnBody []byte
--- /dev/null
+// -
+// ========================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)
+ }
+ }
+
+}
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{
},
},
}
+
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
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)
}
-
}