Skip to content
README.md 28.6 KiB
Newer Older
Rafael Direito's avatar
Rafael Direito committed


# Proof of Concept

## Candidate CAMARA API - QoD Provisioning

For this first Proof of Concept (PoC), we decided to rely on the [CAMARA QoD Provisioning API](https://editor.swagger.io/?url=https://raw.githubusercontent.com/camaraproject/QualityOnDemand/r1.2/code/API_definitions/qod-provisioning.yaml).
Rafael Direito's avatar
Rafael Direito committed

Such API has the following endpoints:

![CAMARA QoD Swagger](Documentation/Pictures/CAMARA-QoDProvisioning-API-Endpoints.png)
Rafael Direito's avatar
Rafael Direito committed

Last, our solution needs to be deployed in a Kubernetes cluster. A 5G Core is needed for proper implementation as well as your own 5G Core Controller.

The PoC is based on [OSL CAMARAaaS Add-on](). It is recommended to read this before diving into the implementation of the PoC.
Rafael Direito's avatar
Rafael Direito committed

Christos Tranoris's avatar
Christos Tranoris committed
## General concepts of the OSL CAMARAaaS as a TMF Service Specification
Rafael Direito's avatar
Rafael Direito committed

First step is to design and expose the OSL CAMARA API service via the TMF models (Service Specification that can be ordered). The OSL CAMARA API service uses as backend connectivity the OSL message bus (OSL’s Active MQ broker). It exposes the CAMARA API, translates and forwards the requests to TMF Service Inventory model via the service bus. Therefore, considering the interactions that shall take place between the exposed CAMARA API, the Operator’s running 5G Controller Service and the architecture introduced before, the OSL CAMARA API exposure service must interface with OSL’s Active MQ broker. Moreover, for this first prototype the OSL's CAMARAaaS will be delivered via a Service Order. To enable this, we need to design it in OpenSlice as a Service Specification, so in general some TMF service characteristics are required to pass this information to the OSL CAMARA API exposure service which will be orchestrated, deployed and configured through OSL:
Rafael Direito's avatar
Rafael Direito committed

- messageBroker.address - OSL's ActiveMQ Address (e.g. 10.10.10.10)
- messageBroker.port - OSL's ActiveMQ Port
- messageBroker.username - OSL’s ActiveMQ Username
- messageBroker.password - OSL’s ActiveMQ Password

Additionally, we also need another Service Characteristic to store the UUID of the Operator’s running 5G Controller Service that will be triggered through the CAMARA API:
Rafael Direito's avatar
Rafael Direito committed

- serviceUnderControl.uuid

Considering that the CAMARA API will be orchestrated by OSL, the client does not know where the API will be deployed, nor the credentials used to access it. Therefore, 4 additional characteristics are required. These will be automatically updated by OSL after the CAMARA API Service is deployed:
Rafael Direito's avatar
Rafael Direito committed

- camaraAPI.url - URL of the CAMARA API orchestrated by this service (view-only). This field will be automatically populated when the CAMARA API starts running
- camaraAPI.username - Username of the CAMARA API orchestrated by this service (view-only). This field will be automatically populated when the CAMARA API starts running
- camaraAPI.password - Password of the CAMARA API orchestrated by this service (view-only). This field will be automatically populated when the CAMARA API starts running
- camaraAPI.status - This characteristic (view-only) will be populated with the CAMARA API status (RUNNING, NOT_RUNNING)

Additionally, you may create a characteristic titled “*camaraAPI.results*”, which you can use to have visibility of the QoD Provisionings processed by the API, at OSL level. Still, this characteristic is not required.

Therefore, OSL’s CAMARAaaS (QoD API exposure service) will contain the following TMF Service Characteristics:
Rafael Direito's avatar
Rafael Direito committed

- messageBroker.address
- messageBroker.port
- messageBroker.username
- messageBroker.password
- serviceUnderControl.uuid
- camaraAPI.url
- camaraAPI.username
- camaraAPI.password
- camaraAPI.status
- camaraAPI.results

### Broker Connection

This API has a *ServiceEventManager* class that communicates with OSL's ActiveMQ broker through two topics:

- `CATALOG.UPD.SERVICE`: Topic for catalog updates.
- `EVENT.SERVICE.ATTRCHANGED`: Topic for service attribute changes.

Christos Tranoris's avatar
Christos Tranoris committed
### CATALOG.UPD.SERVICE
Whenever a new provisioning is created for an UE, the *ServiceEventManager*'s *update_service* method is called. This method sends a service update message through OpenSlice's *CATALOG.UPD.SERVICE* topic. When OSL receives the request, it updates the Operator's 5G Controller Service with the new characteristics, which are then caught and materialized by the correspondent Kubernetes Operator. After processing the request, the Operator adds the result to the CR-related service characteristic, i.e. *camaraResults*.
Christos Tranoris's avatar
Christos Tranoris committed
### EVENT.SERVICE.ATTRCHANGED
The *ServiceEventManager* subscribes to this topic to obtain and process the update messages regarding the specified Operator's 5G Controller Service, namely the UE QoD Profile Enforcer OSL service. Whenever this service's characteristics are updated in OSL, this class catches the update message. Then, the class extracts the *camaraResults* characteristic, which contains all QoS provisionings applied to the UE(s). 

These results are then processed by the *CamaraResultsProcessor* class, which updates each provisioning accordingly in the database.

## General concepts of the QoD service (the 5G Core Provider/Operator Service) and its design as OSL TMF Service Specification
Christos Tranoris's avatar
Christos Tranoris committed

Having chosen the candidate API, the first step is to find a way to map the possible requests to TMF Service characteristics of the Operator’s service. Our approach in general is the following:
Rafael Direito's avatar
Rafael Direito committed

- Design the QoD service that will accept the necessary QoD related characteristics
- Implement the QoD service as a controller able to manage your 5G Core
Christos Tranoris's avatar
Christos Tranoris committed
- Deploy it in a kubernetes cluster that OSL can manage (via CRIDGE)
Rafael Direito's avatar
Rafael Direito committed

Christos Tranoris's avatar
Christos Tranoris committed
By looking at API’s specification, it is clear that at least 3 operations are required: (i) the creation of a QoD profile, (ii) its deletion, and (iii) listing all active QoD profiles. Therefore, we can proceed with evaluating the payload required for creating a QoD Provisioning. This payload involves various fields, which can be translated to the TMF Service Characteristics:

- *qodProv.device.phoneNumber*
- *qodProv.device.networkAccessIdentifier*
- *qodProv.device.ipv4Address.privateAddress*
- *qodProv.device.ipv4Address.publicAddress*
- *qodProv.device.ipv4Address.publicPort*
- *qodProv.device.ipv6Address*
- *qodProv.qosProfile*
- *qodProv.sink*
- *qodProv.sinkCredential.credentialType*

In order to support interaction with the previously defined OSL’s CAMARAaaS and alignment the CAMARA QoD Provisioning API models in general, the QoD service must be designed, at least, with these characteristics. 
Christos Tranoris's avatar
Christos Tranoris committed

Still, since there are various operations that can take place (CREATE and DELETE), a characteristic is also needed to map this. Therefore, the Operator's QoD service must also have a characteristics titled *qodProv.operation*. The DELETE operation is achieved based on a provisioning Id, and therefore the respective characteristics is needed: *qodProv.provisioningId.*
Christos Tranoris's avatar
Christos Tranoris committed

Finally, characteristic is required to store the provisionings that were enforced by the Operator's QoD service. We can define this characteristic as *camaraResults*.
Christos Tranoris's avatar
Christos Tranoris committed

Therefore, for an Operator’s service to be controlled by OSL’s CAMARAaaS specification, it needs to be designed with, at least, the following characteristics:
Christos Tranoris's avatar
Christos Tranoris committed

- *qodProv.device.phoneNumber*
- *qodProv.device.networkAccessIdentifier*
- *qodProv.device.ipv4Address.privateAddress*
- *qodProv.device.ipv4Address.publicAddress*
- *qodProv.device.ipv4Address.publicPort*
- *qodProv.device.ipv6Address*
- *qodProv.qosProfile*
- *qodProv.sink*
- *qodProv.sinkCredential.credentialType*
- *qodProv.operation*
- *qodProv.provisioningId*
- *camaraResults*

Additional characteristics are fully supported. Those can be custom characteristics that are required by the Operator's QoD Service.
Christos Tranoris's avatar
Christos Tranoris committed

In regard to the *camaraResults* characteristic, to allow interoperability, it must store a Stringified JSON Array with the enforced QoD Provisionings. **The schema of each provisioning should be the one defined in CAMARA’s QoD Provisioning API Specification.** 


## How To / Demonstration
Christos Tranoris's avatar
Christos Tranoris committed

### 1. Dummy QoD Kubernetes Operator Service Design
Christos Tranoris's avatar
Christos Tranoris committed

For this prototype, since we cannot deliver a QoD Service implementation for a specific commercial core, we created a Dummy QoD Kubernetes Operator Service which emulates the 5G Core configuration. In future releases of OSL we will offer solutions for some open source 5G cores, and/or some code templates to build your own 5G Core Operator.
Christos Tranoris's avatar
Christos Tranoris committed

We will start by looking at the Dummy QoD Kubernetes Operator Service we have created to demonstrate this Add-on. The Service will be offered as a simple Custom Resource (CR) deployed in a Kubernetes cluster. You may find its Custom Resource Definition (CRD) under `/DummyOperatorService/crd.yaml` Look at the CRD fields. Please notice that these were defined according with what we introduced in the previous section.
Rafael Direito's avatar
Rafael Direito committed

The first step is then to install this CRD in your kubernetes cluster. To this end, you may use the following command: `make create-dummy-operator-crd`

After creating the CRD in your Kubernetes cluster, you may access OSL’s Resource Inventory and you will see the just created resource there.

![](./Documentation/Pictures/DummyOperatorService-ResourceInventory.png)

We need now to start offering this as-a-Service, ready to be ordered from the Service Catalogue. So, the first step is to create a Resource-Facing-Service (RFS) Specification to expose this resource. To do so, you may read the [Exposing Kubernetes Operators as a Service : Offering "Calculator as a Service" through OpenSlice](https://osl.etsi.org/documentation/latest/service_design/examples/ExposingCRDs_aaS_Example_Calculator/ExposingCRDs_aaS_Example_Calculator/) documentation page.
Rafael Direito's avatar
Rafael Direito committed

Regarding the RFS Service, you must set the following characteristics:

- _CR_CHECKVAL_AVAILABLE = RUNNING
- _CR_CHECK_FIELD = spec.status

By setting these characteristics, you will rely on the value of `spec.status` to set the service as `active`. Ideally, the 5G Core provider would have implemented a proper Kubernetes Operator for this Custom Resource to implement the requested QoD. However, as discussed already, for demonstration purposes, we will short-circuit the behavior and we will set `spec.status` to `RUNNING` immediately after deployment.

Then, you can proceed to create a Customer-Facing-Service (CFS) Specification, which will incorporate the just created RFS Service. More information is available at: [Exposing Kubernetes Operators as a Service : Offering "Calculator as a Service" through OpenSlice](https://osl.etsi.org/documentation/latest/service_design/examples/ExposingCRDs_aaS_Example_Calculator/ExposingCRDs_aaS_Example_Calculator/). To create the CFS Service's characteristics, you may use the Service Specification available at `/DummyOperatorService/OSLArtifacts/DummyOperatorService-CFS-Specification.json` . You may manually create the CFS Service, or you may onboard this Service Specification by making a POST request to *[{{url}}/tmf-api/serviceCatalogManagement/v4/serviceSpecification](https://www.notion.so/CAMARAaaS-OSL-15e11fa2ed8d80808254c87d9393cf51?pvs=21).*
After creating the CFS Specification, you should mark this Service as a Bundle. Then, go to “Service Specification Relationships” and add the previous created RFS Specification.
Rafael Direito's avatar
Rafael Direito committed

Regarding the LCM Rules for the CFS Service, you should configure the following ones:


**[Pre-Provision Rule] - Short-circuits RFS/Sets RFS's spec.status to "Running"**
Rafael Direito's avatar
Rafael Direito committed

![](./Documentation/Pictures/DummyOperatorService-Pre-Provision-Rule.png)

```java
{
java.util.HashMap<String,String> charvals = new java.util.HashMap<>();
charvals.put("_CR_SPEC",String.format("""
apiVersion: org.etsi.osl/v1
kind: DummyOperatorService
metadata:
  name: _to_be_replaced_by_osl
  namespace: default
spec:
  status: "%s"
"""
, "RUNNING"));
setServiceRefCharacteristicsValues("Dummy Operator Service - RFS", charvals);
}
```

**[Supervision Rule] - Detects changes to the Operator's CFS and reflects them and forwards them to RFS**
Rafael Direito's avatar
Rafael Direito committed

![](./Documentation/Pictures/DummyOperatorService-Supervision-Rule.png)

```java
{
java.util.HashMap<String,String> charvals = new java.util.HashMap<>();
charvals.put("_CR_SPEC",String.format("""
apiVersion: org.etsi.osl/v1
kind: DummyOperatorService
metadata:
  name: _to_be_replaced_by_osl
  namespace: default
spec:
  qodProv:
    operation: "%s"
    provisioningId: "%s"
    device:
      phoneNumber: "%s"
      networkAccessIdentifier: "%s"
      ipv4Address:
        publicAddress: "%s"
        privateAddress: "%s"
        publicPort: %d
      ipv6Address: "%s"
    qosProfile: "%s"
    sink: "%s"
    sinkCredential:
      credentialType: "%s"
"""
, getCharValAsString("qodProv.operation"), getCharValAsString("qodProv.provisioningId"), getCharValAsString("qodProv.device.phoneNumber"), getCharValAsString("qodProv.device.networkAccessIdentifier"), getCharValAsString("qodProv.device.ipv4Address.publicAddress"), getCharValAsString("qodProv.device.ipv4Address.privateAddress"), getCharValNumber("qodProv.device.ipv4Address.publicPort"), getCharValAsString("qodProv.device.ipv6Address"), getCharValAsString("qodProv.qosProfile"), getCharValAsString("qodProv.sink"), getCharValAsString("qodProv.sinkCredential.credentialType")));
setServiceRefCharacteristicsValues("Dummy Operator Service - RFS", charvals);
}
setCharValFromStringType("camaraResults", getServiceRefPropValue("Dummy Operator Service - RFS", "serviceCharacteristicValue", "spec.camaraResults"));

```

You can find the  `_CR_SPEC` template used for the pre-provision rule at `/DummyOperatorService/OSLArtifacts/cr-template-pre-provision.yaml` . The `_CR_SPEC` template used for the supervision rule is available at `/DummyOperatorService/OSLArtifacts/cr-template-supervision.yaml` 

After that, you may expose this service via OSL’s Service Catalog, and order it. You do not need to configure any characteristics when ordering this Service. Confirm that the Service Order was completed, both RFS and CFS Services are active, and a Custom Resource of type *DummyOperatorService* was created in your Kubernetes Cluster. See images below:
Rafael Direito's avatar
Rafael Direito committed

![DummyOperatorService-ServiceOrder.png](./Documentation/Pictures/DummyOperatorService-ServiceOrder.png)

![DummyOperatorService-ServiceOrder.png](./Documentation/Pictures/DummyOperatorService-CustomResource.png)

### 2. OSL CAMARAaaS QoD Provisioning API exposure Service Design
Then, we can proceed to design the CAMARAaaS QoD Provisioning API exposure Service Specification in OSL catalogue. To this end, OSL’s team has implemented in Python the CAMARAaaS QoD Provisioning API, created a CRD to offer it, and developed a Kubernetes Operator to deal with its internal logic. Start by packaging the API in a docker image and pushing it to a docker repository.
Open the file `Makefile` and update the repository to where you will push the docker image. Update the variable `REPOSITORY_HOST`. You may also choose to update the other variables, but it is not required. After this, run  `make api-docker-image`. This command will build, tag, and push the API docker image to the repository you chose.
#### 2.1 OSL CAMARAaaS QoD Provisioning API - Kubernetes Operator
The previous docker image shall make available the CAMARA QoD Provisioning API. However, these API will be made available through Custom Resources of Type `CAMARAaaS-QoDProvisiongAPI`. Therefore, we also need a Kubernetes Operator to manage these resources. The Operator’s code can be found under `/QoDProvisioningAPI/Operator`. There, you have the source code of the Kubernetes Operator, as well as an Helm Chart to install it.
Start by building and pushing the Kubernetes Operator’s docker image to your repository. Run `make operator-docker-image`. Then, install the operator in your Kubernetes cluster. This action will result in the creation of the CRD for the CAMARA QoD Provisioning API Resources, and deploy the operator in the cluster. It is this operator that will manage the CAMARA QoD Provisioning API Resources, being responsible, for instance, for the deployment a Kubernetes pod and service that expose the CAMARA QoD Provisioning API. To install the Operator, run the following command: 
Rafael Direito's avatar
Rafael Direito committed

```bash
helm install camaraaas-qod-prov-operator ./QoDProvisioningAPI/Operator/chart --set operator.image=<your_operator_image> --set camaraQoDAPI.image=<your_api_image>  --namespace <namespace_where_the_operator_shall_be_deployed> --create-namespace
```

To simplify things, you may also run: `make install-operator`. After this, check if the operator is running through the `make get-operator-logs` command. 
Rafael Direito's avatar
Rafael Direito committed

If everything went ok, you should have a new CRD in your Kubernetes cluster. Run this command to verify if it was created:  `kubectl describe crd camaraaas-qod-provisioning-apis.org.etsi.osl`.

Before designing the service in OSL, let us first create a CR of type `CAMARAaaS-QoDProvisiongAPI` to validate that the operator is behaving according to what is expected. To this end, you may use the test custom resource available at `/QoDProvisioningAPI/Operator/test-cr.yaml` . Before creating the resource, you need to update the fields: *spec.messageBroker.address*, *spec.messageBroker.port, spec.messageBroker.username, spec.messageBroker.password*, with the values that relate with your OSL instance. The default values will be the following ones:
Rafael Direito's avatar
Rafael Direito committed

- *spec.messageBroker.address: <your OSL address>*
- s*pec.messageBroker.port*: 61613
- *spec.messageBroker.username: artemis*
- *spec.messageBroker.password: artemis*

For now, you do not need to update the field serviceUnderControl.uuid. You may leave it as is.

After these updates, create the CR by running the command: `make create-operator-test-cr`. 
When the CR is created, its operator will deploy the CAMARA QoD API in a pod and expose it via a K8s Node Port. The URL where the API is available is published under the CR field `spec.camaraAPI.url` (e.g. [http://10.255.28.73:32630](http://10.255.28.73:32630/)). Check this field by running `make describe-operator-test-cr`. To confirm the API is running, access *<URL>/docs*. You should see the following:
Rafael Direito's avatar
Rafael Direito committed

![](./Documentation/Pictures/QoDProvisioningAPI-Docs.png)

If you see this page, the CAMARA QoD Provisioning API Custom Resources and their operator is working. You may delete the Custom Resource you created. Run the following command: `make delete-operator-test-cr`.

#### 2.2 OSL CAMARAaaS QoD Provisioning API - TMF Service Specification Design
Now we can proceed to create an OSL TMF Service Specification that maps the CAMARAaaS QoD Provisioning API CR, ready to be ordered in your OSL Service Specification Catalogue.
The first step is to create an RFS Service to expose this resource. To do so, you may read the [Exposing Kubernetes Operators as a Service : Offering "Calculator as a Service" through OpenSlice](https://osl.etsi.org/documentation/latest/service_design/examples/ExposingCRDs_aaS_Example_Calculator/ExposingCRDs_aaS_Example_Calculator/) documentation page. 
Rafael Direito's avatar
Rafael Direito committed

Regarding the RFS Service, you must set the following characteristics:

- _CR_CHECKVAL_AVAILABLE = RUNNING
- _CR_CHECK_FIELD = spec.camaraAPI.status

By setting this characteristics, you will rely on the value of `spec.camaraAPI.status` to set the service as `active`. The previous operator, when it deploys the CAMARA QoD Provisioning API will set that CR field to `RUNNING`.

Then, you can proceed to create a CFS Service, which will incorporate the just created RFS Service. More information is available at: [Exposing Kubernetes Operators as a Service : Offering "Calculator as a Service" through OpenSlice](https://osl.etsi.org/documentation/latest/service_design/examples/ExposingCRDs_aaS_Example_Calculator/ExposingCRDs_aaS_Example_Calculator/). To create the CFS Service characteristics, you may use the Service Specification available at `/QoDProvisioningAPI/OSLArtifacts/CAMARAaaS-QoD-Provisioning-API-CFS-Specification.json`. You may manually create the CFS Service, or you may onboard this Service Specification by making a POST request to *[{{url}}/tmf-api/serviceCatalogManagement/v4/serviceSpecification](https://www.notion.so/CAMARAaaS-OSL-15e11fa2ed8d80808254c87d9393cf51?pvs=21).*
Rafael Direito's avatar
Rafael Direito committed

After creating the Service Specification, you should mark this Service as a Bundle. Then, go to “Service Specification Relationships” and add the RFS Service.

Regarding the LCM Rules for the CFS Service, you should configure the following ones:

**[Pre-Provision Rule] - Forwards the user input towards the created CR of type "CAMARAaaS-QoDProvisiongAPI"**
Rafael Direito's avatar
Rafael Direito committed

![](./Documentation/Pictures/CAMARAaaS-QoD-Prov-API-Pre-Provision-Rule.png)

```java
{
java.util.HashMap<String,String> charvals = new java.util.HashMap<>();
charvals.put("_CR_SPEC",String.format("""
apiVersion: org.etsi.osl/v1
kind: CAMARAaaS-QoDProvisiongAPI
metadata:
  name: _to_be_replaced_by_osl_
spec:
  messageBroker:
    address: "%s"
    port: %d
    username: "%s"
    password: "%s"
  serviceUnderControl:
    uuid: "%s"
"""
, getCharValAsString("messageBroker.address"), getCharValNumber("messageBroker.port"), getCharValAsString("messageBroker.username"), getCharValAsString("messageBroker.password"), getCharValAsString("serviceUnderControl.uuid")));
setServiceRefCharacteristicsValues("CAMARAaaS - QoD Provisioning API - RFS", charvals);
}

```

**[Supervision Rule] - Updates the exposed QoD Provisioning API Service with information about the undertaken actions**
Rafael Direito's avatar
Rafael Direito committed

![CAMARAaaS-QoD-Prov-API-Supervision-Rule.png](./Documentation/Pictures/CAMARAaaS-QoD-Prov-API-Supervision-Rule.png)

```java
{
java.util.HashMap<String,String> charvals = new java.util.HashMap<>();
charvals.put("_CR_SPEC",String.format("""
apiVersion: org.etsi.osl/v1
kind: CAMARAaaS-QoDProvisiongAPI
metadata:
  name: _to_be_replaced_by_osl_
spec:
  messageBroker:
    address: "%s"
    port: %d
    username: "%s"
    password: "%s"
  serviceUnderControl:
    uuid: "%s"
"""
, getCharValAsString("messageBroker.address"), getCharValNumber("messageBroker.port"), getCharValAsString("messageBroker.username"), getCharValAsString("messageBroker.password"), getCharValAsString("serviceUnderControl.uuid")));
setServiceRefCharacteristicsValues("CAMARAaaS - QoD Provisioning API - RFS", charvals);
}
setCharValFromStringType("camaraAPI.status", getServiceRefPropValue("CAMARAaaS - QoD Provisioning API - RFS", "serviceCharacteristicValue", "spec.camaraAPI.status"));
setCharValFromStringType("camaraAPI.url", getServiceRefPropValue("CAMARAaaS - QoD Provisioning API - RFS", "serviceCharacteristicValue", "spec.camaraAPI.url"));
setCharValFromStringType("camaraAPI.username", getServiceRefPropValue("CAMARAaaS - QoD Provisioning API - RFS", "serviceCharacteristicValue", "spec.camaraAPI.username"));
setCharValFromStringType("camaraAPI.password", getServiceRefPropValue("CAMARAaaS - QoD Provisioning API - RFS", "serviceCharacteristicValue", "spec.camaraAPI.password"));
setCharValFromStringType("camaraAPI.results", getServiceRefPropValue("CAMARAaaS - QoD Provisioning API - RFS", "serviceCharacteristicValue", "spec.camaraAPI.results"));

```

You can find the  `_CR_SPEC` template used for both rules at `/QoDProvisioningAPI/OSLArtifacts/cr-template.yaml`. 
Rafael Direito's avatar
Rafael Direito committed

After that, you may expose this service via OSL’s Service Catalog, and order it. When you order it, you will be prompted to configure some characteristics:

- messageBroker.address
- messageBroker.port
- messageBroker.username
- messageBroker.password
- serviceUnderControl.uuid

In `serviceUnderControl.uuid` you should input the UUID of the Service (in the Service Inventory) that you ordered before: the one that relates with the Dummy Operator. For this tutorial, we have used the following characteristic values:


![CAMARAaaS-QoD-Prov-API-Ordering.png](./Documentation/Pictures/CAMARAaaS-QoD-Prov-API-Ordering.png)

Confirm that the service order was completed, both RFS and CFS Services are active, and a Custom Resource of type CAMARAaaS-QoDProvisiongAPI was created in your Kubernetes Cluster. See images below (`kubectl describe camaraaas-qod-provisioning-apis <name> -n <namespace>`)

![](./Documentation/Pictures/CAMARAaaS-QoD-Prov-API-Active-Services.png)

![](./Documentation/Pictures/CAMARAaaS-QoD-Prov-API-CR.png)

Additionally, in OSL, you may see the URL where the QoD Provisioning API is exposed. To do so, please see the characteristics of the CAMARAaaS QoD Provisioning API CFS. See image below:
Rafael Direito's avatar
Rafael Direito committed

![](./Documentation/Pictures/CAMARAaaS-QoD-Prov-API-Characteristics.png)

### 3. Validation
Rafael Direito's avatar
Rafael Direito committed

Now we can test if the two services are communicating. To do so, you should create a QoD Provisioning via the API that was just deployed. You may do that, using this command:

```bash
# You must update the url to correspond to your API instance, found in camaraAPI.url highlighted in previous image.
curl --location '{{camaraAPI.url}}/device-qos' \
Rafael Direito's avatar
Rafael Direito committed
--header 'Content-Type: application/json' \
--data-raw '{
  "device": {
    "phoneNumber": "+987654321",
    "networkAccessIdentifier": "987654321@example.org",
    "ipv4Address": {
      "publicAddress": "203.0.112.12",
      "publicPort": 59765
    },
    "ipv6Address": "2001:db8:85a3:8d3:1319:8a2e:370:7344"
  },
  "qosProfile": "QOS_PROFILE_A",
  "sink": "https://endpoint.example.com/"
}'
```

You should have received a response similar to this one: 

```bash
{"device":{"phoneNumber":"+987654321","networkAccessIdentifier":"987654321@example.org","ipv4Address":{"publicAddress":"203.0.112.12","privateAddress":null,"publicPort":59765},"ipv6Address":"2001:db8:85a3:8d3:1319:8a2e:370:7344"},"qosProfile":"QOS_PROFILE_A","sink":"https://endpoint.example.com/","sinkCredential":{"credentialType":null},"provisioningId":"cb55f9e9-802e-4898-95f5-d1a5a2552483","startedAt":"2024-12-17T15:49:21.995399","status":"REQUESTED","statusInfo":null}
```

Now, if everything is working properly, the characteristics of the Dummy Operator Service you referenced should have been updated. You should now see these characteristics:
Rafael Direito's avatar
Rafael Direito committed

![DummyOperatorService-Characteristics-After-CAMARA-Invoking.png](./Documentation/Pictures/DummyOperatorService-Characteristics-After-CAMARA-Invoking.png)

You may also query the  QoD Provisioning API to check the status of your provisioning.

```bash
curl --location '{{camaraAPI.url}}/device-qos/cb55f9e9-802e-4898-95f5-d1a5a2552483'
Rafael Direito's avatar
Rafael Direito committed
# notice the "provisioningId":"cb55f9e9-802e-4898-95f5-d1a5a2552483" above
```

If you do so, you will receive the following response:

```bash
{"device":{"phoneNumber":"+987654321","networkAccessIdentifier":"987654321@example.org","ipv4Address":{"publicAddress":"203.0.112.12","privateAddress":null,"publicPort":59765},"ipv6Address":"2001:db8:85a3:8d3:1319:8a2e:370:7344"},"qosProfile":"QOS_PROFILE_A","sink":"https://endpoint.example.com/","sinkCredential":{"credentialType":null},"provisioningId":"cb55f9e9-802e-4898-95f5-d1a5a2552483","startedAt":"2024-12-17T15:49:21.962746","status":"REQUESTED","statusInfo":null}
```

As there is no logic behind the Dummy Operator Service, the provisioning will remain with the status “REQUESTED”. However, we can simulate that Dummy Operator Service enforced a QOS enforcement, by patching its Custom Resource:

```bash
kubectl patch dummy-operator-services <name> -n <namespace> \
--type='json' -p='[{"op": "replace", "path": "/spec/camaraResults", "value": "[{\"device\": {\"ipv4Address\": {\"publicAddress\": \"203.0.112.12\", \"publicPort\": 59765}, \"ipv6Address\": \"2001:db8:85a3:8d3:1319:8a2e:370:7344\", \"networkAccessIdentifier\": \"987654321@example.org\", \"phoneNumber\": \"+987654321\"}, \"provisioningId\": \"cb55f9e9-802e-4898-95f5-d1a5a2552483\", \"qosProfile\": \"QOS_PROFILE_A\", \"sink\": \"https://endpoint.example.com/\", \"sinkCredential\": {}, \"status\": \"AVAILABLE\", \"startedAt\": \"2024-12-15T11:00:00Z\"}]"}]'
```

When you do this, the `camaraResults` characteristic in the Dummy Operator Service will be updated to:

![](./Documentation/Pictures/DummyOperatorService-Characteristics-After-CAMARA-Invoking.png)

After a while, if you check the characteristics of the CAMARAaaS QoD Provisioning API CFS, you will also see that the characteristic `camaraAPI.results` was updated.

![](./Documentation/Pictures/CAMARAaaS-QoD-Prov-API-Characteristics-After-CAMARA-Invoking.png)

Finally, execute this request again:

```bash
curl --location '{{camaraAPI.url}}/device-qos/cb55f9e9-802e-4898-95f5-d1a5a2552483'
Rafael Direito's avatar
Rafael Direito committed
# notice the "provisioningId":"cb55f9e9-802e-4898-95f5-d1a5a2552483" above
```

You should receive the following response.

```bash
{"device":{"phoneNumber":"+987654321","networkAccessIdentifier":"987654321@example.org","ipv4Address":{"publicAddress":"203.0.112.12","privateAddress":null,"publicPort":59765},"ipv6Address":"2001:db8:85a3:8d3:1319:8a2e:370:7344"},"qosProfile":"QOS_PROFILE_A","sink":"https://endpoint.example.com/","sinkCredential":{"credentialType":null},"provisioningId":"cb55f9e9-802e-4898-95f5-d1a5a2552483","startedAt":"2024-12-15T11:00:00","status":"AVAILABLE","statusInfo":null}
```

Notice the `"status":"AVAILABLE"`. This means the 2 services are communicating. 
Christos Tranoris's avatar
Christos Tranoris committed


Now, you just have to implement your own Kubernetes Operator for your 5G Core configuration, and you may use OSL’s CAMARAaaS Add-on to expose it through a CAMARA API.