Skip to end of metadata
Go to start of metadata



Pre requisite
  • Near Realtime RIC installation completed
  • Near Realtime RIC up and running

   # kubectl get pods -n ricplt   # There should be ~16 pods running in the ricplt namespace.  

Step 1: Prep Tasks (Preparing for xApp on-boarding)

Each xApp is required to provide a "descriptor".   The descriptor is used by the Near RT RIC xApp On-boarder to generate a Helm chart and other deployment related artifacts for the xapp.  At this step we are preparing for API calls into the xApp On-Boarder by providing thee locations of the xApp descriptors.

Run ...

$ sudo -i
# Working directory will be dep where near realtime ric is deployed

$ cd dep
$ echo '{"config-file.json_url": ";a=blob_plain;f=xapp-descriptor/config.json;hb=HEAD" }' > onboard.qp.url
$ echo '{"config-file.json_url": ";a=blob_plain;f=xapp-descriptor/config.json;hb=HEAD" }' > onboard.qpd.url
$ echo '{"config-file.json_url": ";a=blob_plain;f=xapp-descriptor/config.json;hb=HEAD" }' > onboard.ts.url
Step 2: Onboard xApps

Now we invoke API calls into the xApp On-boarder, providing it the locations of the xApp descripters.


$ curl --location --request POST "http://$(hostname):32080/onboard/api/v1/onboard/download"      --header 'Content-Type: application/json' --data-binary "@./onboard.ts.url
$ curl --location --request POST "http://$(hostname):32080/onboard/api/v1/onboard/download"      --header 'Content-Type: application/json' --data-binary "@./onboard.qp.url"
$ curl --location --request POST "http://$(hostname):32080/onboard/api/v1/onboard/download"      --header 'Content-Type: application/json' --data-binary "@./onboard.qpd.url"
# checking what have been on-boarded
$ curl --location --request GET "http://$(hostname):32080/onboard/api/v1/charts"
Step 3:  Deploy xApp

At this step, we deploy the xApps by invoking the xApp Manager's API.  Note that the names of the xApp to be deployed must match with what the on-boarder has.  Once receiving the deploy API call, the xApp Manager will make API call into Helm/Kubernetes to deploy the xApp's Helm chart.  The Routing Manager is also involved if the xApp is to process RMR messages, – it will compote the routes and send out route updates.

Run ...

$ curl --location --request POST "http://$(hostname):32080/appmgr/ric/v1/xapps"      --header 'Content-Type: application/json' --data-raw '{"xappName": "qp"}'
$ curl --location --request POST "http://$(hostname):32080/appmgr/ric/v1/xapps"      --header 'Content-Type: application/json' --data-raw '{"xappName": "qpdriver"}'
$ curl --location --request POST "http://$(hostname):32080/appmgr/ric/v1/xapps"      --header 'Content-Type: application/json' --data-raw '{"xappName": "trafficxapp"}'
# now check the running state of these xApps
$ kubectl get pods -n ricxapp
Step 4: Populate the Database with test RAN data

This step is needed for the phase one of the Traffic Steering use case.  In phase one, the RAN data is artificial and the data points need to be injected into RNIB database.  After these artificial data points are injected, we should see the Traffic Steering xApp starting to process these data, using the default threshold of 0.

Run ...

$ git clone -b bronze
$ cd ts/test/populatedb
$  ./
Step 5:  Create a Policy Type

Here we define a new policy type and call the A1 mediator to create such a policy type.

Run ...

$ cd ~/dep/
$ POLICY_TYPE_ID="20008"
$ echo '{ "name": "tsapolicy", "description": "tsa parameters", "policy_type_id": 20008, "create_schema": { "$schema": "", "title": "TS Policy", "description": "TS policy type", "type": "object", "properties": { "threshold": { "type": "integer", "default": 0 } }, "additionalProperties": false } } ' > ts-policy-type-20008.json
$ curl -v -X PUT "http://$(hostname):32080/a1mediator/a1-p/policytypes/${POLICY_TYPE_ID}"   -H "accept: application/json" -H "Content-Type: application/json"   -d @./ts-policy-type-${POLICY_TYPE_ID}.json
Step 6:  List Policy Types

We now should see the newly created policy type when querying the A1 mediator.

Run ...

$ curl -X GET --header "Content-Type: application/json" --header "accept: application/json"   http://$(hostname):32080/a1mediator/a1-p/policytypes
Step 7:  Create a Policy Instance

Policy type is merely a declaration.  Now we create a policy instance, filling the properties with actual values.  This is also carried out by the A1 mediator. 

A1 mediator will distribute the new policy instance to the Traffic Steering xApp. 

And then we should see that the TS xApp receives this policy instancee and its behavior of "filtering RAN data by threshold" changing to using the new threshold value.


$ POLICY_ID="tsapolicy145"
$ curl -X PUT --header "Content-Type: application/json"   --data "{\"threshold\" : 5}"   http://$(hostname):32080/a1mediator/a1-p/policytypes/${POLICY_TYPE_ID}/policies/${POLICY_ID}
Tutorial Videos

Hello World xApp xapp-hw.mp4

Helpful Hints

Kubectl commads:

kubectl get pods -n nampespace - gets a list of Pods running

kubectl get logs -n namespace name_of_running_pod

Complete these tasks to get started

Recent space activity

Space contributors


  • No labels


  1. Hi Lusheng,

    Thanks for the RIC XAPP deployment guide.

    I was able to deploy all the xAPPs except QP driver.

    I have the following error when I try to onboard using  curl --location --request POST "http://$(hostname):32080/appmgr/ric/v1/xapps"      --header 'Content-Type: application/json' --data-raw '{"xappName": "qpdriver"}'

    "error_source": "config-file.json",
    "error_message": "'__empty_control_section__' is a required property",
    "status": "Input payload validation failed"

    I think the error is from the descriptor of the version 1.0.9 located at onboard.qpd.url

    But when I changed the qpdriver version to 1.0.0 it works;a=blob_plain;f=xapp-descriptor/config.json;h=94582086d02df6299dd902556aa2e2111ed94268;hb=4074973dbbe90e11643c229fff39bb8a6f662dc8


    1. Anonymous


      This can be resolved by deleting lines 38-41.

      "controls": {
      "example_int": 10000,
      "example_str": "value"

      --Cornellius Dagmang

  2. Hi Luseng,

    I have created multiple policies while testing & want to delete those policies from Nonrt dashboard GUI. I have used below command to delete

    curl -X DELETE --header "Content-Type: application/json" --header "accept: application/json"

    By using above command it is getting deleted from VM but not Nonrt dashboard GUI. Please guide me the command to delete policies from Nonrt dashboard GUI.

    Thanks ,


  3. After onboarding all the xApps, there is a error sending message from ts-xapp

    In get_sdl_ue_data()
    message body {"UEPredictionSet": ["12345"]}
    payload length 30
    <SNDR> send failed: 2

    Any known fixes/workarounds?

      1. Here is the normal output:

        In get_sdl_ue_data()
        message body {"UEPredictionSet": ["12345"]}
        payload length 30
        Prediction Callback got a message, type=30002 , length=182
        payload is { "12345" : { "310-680-200-555001" : [ 2000000 , 1200000 ], "310-680-200-555002" : [ 800000 , 400000 ], "310-680-200-555003" : [ 800000 , 400000 ] } }
        Prediction for 12345

        from the source code:

        void send_prediction_request(vector<string> ues_to_predict) {

        int mtype = 30000;

        // payload updated in place, nothing to copy from, so payload parm is nil
        if ( ! msg->Send_msg( mtype, Message::NO_SUBID, strlen( (char *) send_payload.get() ), NULL )) {
            fprintf( stderr, "<SNDR> send failed: %d\n", msg->Get_state() );


        void prediction_callback( Message& mbuf, int mtype, int subid, int len, Msg_component payload, void* data ) {

        cout << "Prediction Callback got a message, type=" << mtype << " , length=" << len << "\n";
        cout << "payload is " << payload.get() << "\n";


        which means that prediction_callback is not correctly called.

        in tsxapp.main, prediction_callback is binded to MSG_ID=30002.

        extern int main( int argc, char** argv ) {
            xfw->Add_msg_cb( 20010, policy_callback, NULL );
            xfw->Add_msg_cb( 30002, prediction_callback, NULL );

        RMR will route msg with MSG_ID=30000 to qpdriver xapp. qpdriver will process it , and generate another msg with MSG_ID=30001

        rmr_xapp.register_callback(steering_req_handler, 30000)

        success = self.rmr_send(payload, 30001)

        RMR will further route msg with MSG_ID=30001 to qp xapp. qp will process it, and generate another msg with MSG_ID=30002, which will be routed back to tsxapp by RMR.

        qp_xapp.register_callback(qp_predict_handler, 30001)

        success = self.rmr_send(mock_msg.encode(), 30002)

        Based on above analysis, my best guess is that, qp-driver and qp xapp has not been deployed successfully.

  4. Hi Experts,

    I got RMR_ERR_NOENDPT after creating policy instance. Can you pls help? thanks

    RMR_ERR_NOENDPTsend/call could not find an endpoint based on msg type

    here is part of 'kubectl logs -f deployment-ricplt-a1mediator-66fcf76c66-8dxcj -n ricplt':

    ::ffff: - - [2020-08-07 07:41:28] "PUT /a1-p/policytypes/20008/policies/tsapolicy145 HTTP/1.1" 202 116 0.007207

    {"ts": 1596786088608, "crit": "DEBUG", "id": "a1.a1rmr", "mdc": {}, "msg": "_send_msg: sending: {'payload': b'{\"operation\": \"CREATE\", \"policy_type_id\": 20008, \"policy_instance_id\": \"tsapolicy145\", \"payload\": {\"threshold\": 5}}', 'payload length': 115, 'message type': 20010, 'subscription id': 20008, 'transaction id': b'67712138d88111eab3bcd2cb2aea4bae', 'message state': 0, 'message status': 'RMR_OK', 'payload max size': 4096, 'meid': b'', 'message source': 'service-ricplt-a1mediator-rmr.ricplt:4562', 'errno': 0}"}

    {"ts": 1596786088608, "crit": "WARNING", "id": "a1.a1rmr", "mdc": {}, "msg": "RMR send failed; pre-send summary: {'payload': b'{\"operation\": \"CREATE\", \"policy_type_id\": 20008, \"policy_instance_id\": \"tsapolicy145\", \"payload\": {\"threshold\": 5}}', 'payload length': 115, 'message type': 20010, 'subscription id': 20008, 'transaction id': b'67712138d88111eab3bcd2cb2aea4bae', 'message state': 0, 'message status': 'RMR_OK', 'payload max size': 4096, 'meid': b'', 'message source': 'service-ricplt-a1mediator-rmr.ricplt:4562', 'errno': 0}, post-send summary: {'payload': None, 'payload length': 115, 'message type': 20010, 'subscription id': 20008, 'transaction id': b'67712138d88111eab3bcd2cb2aea4bae', 'message state': 2, 'message status': 'RMR_ERR_NOENDPT', 'payload max size': 4096, 'meid': b'', 'message source': 'service-ricplt-a1mediator-rmr.ricplt:4562', 'errno': 6}"}

    {"ts": 1596786088608, "crit": "DEBUG", "id": "a1.a1rmr", "mdc": {}, "msg": "_send_msg: result message state: 2"}

    {"ts": 1596786088608, "crit": "WARNING", "id": "a1.a1rmr", "mdc": {}, "msg": "_send_msg: failed after 20 retries"}

    1. Anonymous

      hi all,

      i rebuild the docker image from "ric-app-ts 1.0.11" of Gerrit, and re-deploy trafficxapp, there is no RMR_ERR_NOENDPT error now.

      ::ffff: - - [2020-08-07 14:12:02] "PUT /a1-p/policytypes/20008/policies/tsapolicy145 HTTP/1.1" 202 116 0.008321
      {"ts": 1596809522972, "crit": "DEBUG", "id": "a1.a1rmr", "mdc": {}, "msg": "_send_msg: sending: {'payload': b'{\"operation\": \"CREATE\", \"policy_type_id\": 20008, \"policy_instance_id\": \"tsapolicy145\", \"payload\": {\"threshold\": 5}}', 'payload length': 115, 'message type': 20010, 'subscription id': 20008, 'transaction id': b'f769383ad8b711eaacd4cac483485e64', 'message state': 0, 'message status': 'RMR_OK', 'payload max size': 4096, 'meid': b'', 'message source': 'service-ricplt-a1mediator-rmr.ricplt:4562', 'errno': 0}"}
      {"ts": 1596809522977, "crit": "DEBUG", "id": "a1.a1rmr", "mdc": {}, "msg": "_send_msg: result message state: 0"}

  5. Anonymous

    Would someone provide prerequisite and instructions to create the xApp??

    1. Please post after you log in to Confluence so people know who you are.

  6. Anonymous

    Can anyone let me know the same steps for Admission Control xAPP

  7. Was the image( used ts/test/Dockerfile removed in nexus?

    I can't find it or its other version for ubuntu18 in nexus

    1. pls refer to ORAN Base Docker Images for CI Builds#Imagebldr-ubuntu18-c-go

      you need: 

      $docker pull

      1. I had tried it before and I could find  bldr-ubuntu18-c-go:9-u18.04 in nexus at that time,

        but there is not bldr-ubuntu18-c-go in nexus now.

        1. Yeah, there is no bldr-ubuntu18-c-go image any more in the repository.

          I propose two solutions:

          (1) you can build the docker image manually and retag it:


          $git clone

          $cd bldr-imgs/bldr-ubuntu18-c-go

          $sudo docker build -t .

          (2) you may pull the image from my docker-hub and retag it:

          $docker pull zhenggao2/bldr-ubuntu18-c-go:9-u18.04

          $docker tag zhenggao2/bldr-ubuntu18-c-go:9-u18.04

          $docker rmi zhenggao2/bldr-ubuntu18-c-go:9-u18.04

Write a comment…