A1-Simulator - Align with OSC Near-RT-RIC A1 Mediator
Issue-ID: NONRTRIC-892
Change-Id: I8123c492e1f3354df15dd107e73ee71a7e28a22d
Signed-off-by: DenisGNoonan <denis.noonan@est.tech>
diff --git a/near-rt-ric-simulator/README.md b/near-rt-ric-simulator/README.md
index b62324e..2369872 100644
--- a/near-rt-ric-simulator/README.md
+++ b/near-rt-ric-simulator/README.md
@@ -59,6 +59,7 @@
| GET, get a policy | http://localhost:8085/a1-p/policytypes/{policy\_type\_id}/policies/{policy\_instance\_id} |
| PUT, create/update a policy | http://localhost:8085/a1-p/policytypes/{policy\_type\_id}/policies/{policy\_instance\_id} |
| GET, get policy status | http://localhost:8085/a1-p/policytypes/{policy\_type\_id}/policies/{policy\_instance\_id}/status |
+| PUT, deliver data produced by data producer | http://localhost:8085/data-delivery json payload = {"job":"101", "payload":"another payload"}|
Swagger UI at: http://localhost:8085/ui/
@@ -82,8 +83,6 @@
| Turn on http header and payload logging | http://localhost:8085payload_logging/on |
| Turn off http header and payload logging | http://localhost:8085payload_logging/off |
-
-
# Supported operations in simulator A1 Standard 1.1.3
For the complete yaml specification, see [STD_A1.yaml](../near-rt-ric-simulator/api/STD_1.1.3/STD_A1.yaml).
@@ -164,7 +163,7 @@
An env variable, REMOTE_HOSTS_LOGGING, can be set (any value is ok) and the the counter remote\_hosts will log the host names of all remote hosts that has accessed the A1 URIs. If host names cannot be resolved, the ip address of the remote host is logged instead. This logging is default off so must be configured to be enabled. If not configured, the counter remote\_hosts will return a fixed text indicating that host name logging is not enabled. Use this feature with caution, remote host lookup may take time in certain environments.
-And optional env variable, DUPLICATE_CHECK, can be set to '1' to turn on duplicate check of policiy json. A duplicate policy is when the policy json is exactly same as for a different policy id of the same type. This function is default set off if the variable is not set at all or set to '0'.
+And optional env variable, DUPLICATE_CHECK, can be set to '1' to turn on duplicate check of policy json. A duplicate policy is when the policy json is exactly same as for a different policy id of the same type. This function is default set off if the variable is not set at all or set to '0'.
The simulator can also run using the https protocol. The enable https, a valid certificate and key need to provided. There is self-signed certificate available in the certificate dir and that dir shall be mounted to the container to make it available
diff --git a/near-rt-ric-simulator/api/OSC_2.1.0/openapi.yaml b/near-rt-ric-simulator/api/OSC_2.1.0/openapi.yaml
index 828a6bf..39af6c8 100644
--- a/near-rt-ric-simulator/api/OSC_2.1.0/openapi.yaml
+++ b/near-rt-ric-simulator/api/OSC_2.1.0/openapi.yaml
@@ -1,7 +1,7 @@
# ==================================================================================
# Copyright (c) 2019-2020 Nokia
# Copyright (c) 2018-2020 AT&T Intellectual Property.
-# Copyright (c) 2020 Nordix Foundation, Modifications
+# Copyright (c) 2020-2023 Nordix Foundation, Modifications
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,311 +15,410 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==================================================================================
-openapi: 3.0.0
+openapi: 3.0.1
info:
- version: 2.1.0
title: RIC A1
+ version: 2.1.0
+servers:
+- url: /
paths:
- '/a1-p/healthcheck':
+ /a1-p/healthcheck:
get:
- description: >
+ tags:
+ - A1 Mediator
+ description: |
Perform a healthcheck on a1
- tags:
- - A1 Mediator
- operationId: a1.get_healthcheck
+ operationId: a1_controller_get_healthcheck
responses:
200:
- description: >
- A1 is healthy.
- Anything other than a 200 should be considered a1 as failing
-
- '/a1-p/policytypes':
+ description: |
+ A1 is healthy. Anything other than a 200 should be considered a1 as failing
+ content: {}
+ /a1-p/policytypes:
get:
- description: "Get a list of all registered policy type ids"
tags:
- - A1 Mediator
- operationId: a1.get_all_policy_types
+ - A1 Mediator
+ description: Get a list of all registered policy type ids
+ operationId: a1_controller_get_all_policy_types
responses:
200:
- description: "list of all registered policy type ids"
+ description: list of all registered policy type ids
content:
application/json:
schema:
type: array
items:
- "$ref": "#/components/schemas/policy_type_id"
- example: [20000, 20020]
+ $ref: '#/components/schemas/policy_type_id'
+ example:
+ - 20000
+ - 20020
503:
- description: "Potentially transient backend database error. Client should attempt to retry later."
-
- '/a1-p/policytypes/{policy_type_id}':
- parameters:
+ description: Potentially transient backend database error. Client should
+ attempt to retry later.
+ content: {}
+ /a1-p/policytypes/{policy_type_id}:
+ get:
+ tags:
+ - A1 Mediator
+ description: |
+ Get this policy type
+ operationId: a1_controller_get_policy_type
+ parameters:
- name: policy_type_id
in: path
+ description: |
+ represents a policy type identifier. Currently this is restricted to an integer range.
required: true
schema:
- "$ref": "#/components/schemas/policy_type_id"
- get:
- description: >
- Get this policy type
- tags:
- - A1 Mediator
- operationId: a1.get_policy_type
+ maximum: 2147483647
+ minimum: 1
+ type: integer
responses:
- '200':
- description: "policy type successfully found"
+ 200:
+ description: policy type successfully found
content:
application/json:
schema:
- "$ref": "#/components/schemas/policy_type_schema"
- '404':
- description: >
+ $ref: '#/components/schemas/policy_type_schema'
+ 404:
+ description: |
policy type not found
- '503':
- description: "Potentially transient backend database error. Client should attempt to retry later."
- delete:
- description: >
- Delete this policy type. Can only be performed if there are no instances of this type
- tags:
- - A1 Mediator
- operationId: a1.delete_policy_type
- responses:
- '204':
- description: >
- policy type successfully deleted
- '400':
- description: >
- Policy type cannot be deleted because there are instances
- All instances must be removed before a policy type can be deleted
- '404':
- description: >
- policy type not found
- '503':
- description: "Potentially transient backend database error. Client should attempt to retry later."
+ content: {}
+ 503:
+ description: Potentially transient backend database error. Client should
+ attempt to retry later.
+ content: {}
put:
- description: >
- Create a new policy type .
- Replace is not currently allowed; to replace, for now do a DELETE and then a PUT again.
-
tags:
- - A1 Mediator
- operationId: a1.create_policy_type
+ - A1 Mediator
+ description: |
+ Create a new policy type . Replace is not currently allowed; to replace, for now do a DELETE and then a PUT again.
+ operationId: a1_controller_create_policy_type
+ parameters:
+ - name: policy_type_id
+ in: path
+ description: |
+ represents a policy type identifier. Currently this is restricted to an integer range.
+ required: true
+ schema:
+ maximum: 2147483647
+ minimum: 1
+ type: integer
requestBody:
content:
application/json:
schema:
- "$ref": "#/components/schemas/policy_type_schema"
- example:
- name: admission_control_policy
- description: various parameters to control admission of dual connection
- policy_type_id: 20000
- create_schema:
- $schema: 'http://json-schema.org/draft-07/schema#'
- type: object
- properties:
- enforce:
- type: boolean
- default: true
- window_length:
- type: integer
- default: 1
- minimum: 1
- maximum: 60
- description: Sliding window length (in minutes)
- blocking_rate:
- type: number
- default: 10
- minimum: 1
- maximum: 100
- description: '% Connections to block'
- trigger_threshold:
- type: integer
- default: 10
- minimum: 1
- description: Minimum number of events in window to trigger blocking
- additionalProperties: false
-
+ $ref: '#/components/schemas/policy_type_schema'
+ required: false
responses:
- '201':
- description: "policy type successfully created"
- '400':
- description: "illegal ID, or object already existed"
- '503':
- description: "Potentially transient backend database error. Client should attempt to retry later."
-
- '/a1-p/policytypes/{policy_type_id}/policies':
- parameters:
+ 201:
+ description: policy type successfully created
+ content: {}
+ 400:
+ description: illegal ID, or object already existed
+ content: {}
+ 503:
+ description: Potentially transient backend database error. Client should
+ attempt to retry later.
+ content: {}
+ x-codegen-request-body-name: body
+ delete:
+ tags:
+ - A1 Mediator
+ description: |
+ Delete this policy type. Can only be performed if there are no instances of this type
+ operationId: a1_controller_delete_policy_type
+ parameters:
- name: policy_type_id
in: path
+ description: |
+ represents a policy type identifier. Currently this is restricted to an integer range.
required: true
schema:
- "$ref": "#/components/schemas/policy_type_id"
+ maximum: 2147483647
+ minimum: 1
+ type: integer
+ responses:
+ 204:
+ description: |
+ policy type successfully deleted
+ content: {}
+ 400:
+ description: |
+ Policy type cannot be deleted because there are instances All instances must be removed before a policy type can be deleted
+ content: {}
+ 404:
+ description: |
+ policy type not found
+ content: {}
+ 503:
+ description: Potentially transient backend database error. Client should
+ attempt to retry later.
+ content: {}
+ /a1-p/policytypes/{policy_type_id}/policies:
get:
- description: "get a list of all policy instance ids for this policy type id"
tags:
- - A1 Mediator
- operationId: a1.get_all_policy_identities
+ - A1 Mediator
+ description: get a list of all policy instance ids for this policy type id
+ operationId: a1_controller_get_all_instances_for_type
+ parameters:
+ - name: policy_type_id
+ in: path
+ description: |
+ represents a policy type identifier. Currently this is restricted to an integer range.
+ required: true
+ schema:
+ maximum: 2147483647
+ minimum: 1
+ type: integer
responses:
200:
- description: "list of all policy instance ids for this policy type id"
+ description: list of all policy instance ids for this policy type id
content:
application/json:
schema:
type: array
items:
- "$ref": "#/components/schemas/policy_instance_id"
- example: ["3d2157af-6a8f-4a7c-810f-38c2f824bf12", "06911bfc-c127-444a-8eb1-1bffad27cc3d"]
- '503':
- description: "Potentially transient backend database error. Client should attempt to retry later."
-
-
- '/a1-p/policytypes/{policy_type_id}/policies/{policy_instance_id}':
- parameters:
+ $ref: '#/components/schemas/policy_instance_id'
+ example:
+ - 3d2157af-6a8f-4a7c-810f-38c2f824bf12
+ - 06911bfc-c127-444a-8eb1-1bffad27cc3d
+ 503:
+ description: Potentially transient backend database error. Client should
+ attempt to retry later.
+ content: {}
+ /a1-p/policytypes/{policy_type_id}/policies/{policy_instance_id}:
+ get:
+ tags:
+ - A1 Mediator
+ description: |
+ Retrieve the policy instance
+ operationId: a1_controller_get_policy_instance
+ parameters:
- name: policy_type_id
in: path
+ description: |
+ represents a policy type identifier. Currently this is restricted to an integer range.
required: true
schema:
- "$ref": "#/components/schemas/policy_type_id"
-
+ maximum: 2147483647
+ minimum: 1
+ type: integer
- name: policy_instance_id
in: path
+ description: |
+ represents a policy instance identifier. UUIDs are advisable but can be any string
required: true
schema:
- "$ref": "#/components/schemas/policy_instance_id"
-
- get:
- description: >
- Retrieve the policy instance
-
- tags:
- - A1 Mediator
- operationId: a1.get_policy_instance
+ type: string
+ - name: notificationDestination
+ in: query
+ description: |
+ URL send by non-RT RIC. This where non-RT RIC expects status updates on the policy creation
+ schema:
+ type: string
responses:
- '200':
- description: >
- The policy instance.
- the schema of this object is defined by the create_schema field of the policy type
+ 200:
+ description: |
+ The policy instance. the schema of this object is defined by the create_schema field of the policy type
content:
application/json:
schema:
type: object
- '404':
- description: >
+ 404:
+ description: |
there is no policy instance with this policy_instance_id or there is no policy type with this policy_type_id
- '503':
- description: "Potentially transient backend database error. Client should attempt to retry later."
-
- delete:
- description: >
- Delete this policy instance
-
- tags:
- - A1 Mediator
- operationId: a1.delete_policy_instance
- responses:
- '202':
- description: >
- policy instance deletion initiated
- '404':
- description: >
- there is no policy instance with this policy_instance_id or there is no policy type with this policy_type_id
- '503':
- description: "Potentially transient backend database error. Client should attempt to retry later."
-
+ content: {}
+ 503:
+ description: Potentially transient backend database error. Client should
+ attempt to retry later.
+ content: {}
put:
- description: >
- Create or replace a policy instance of type policy_type_id.
- The schema of the PUT body is defined by the create_schema field of the policy type.
-
tags:
- - A1 Mediator
- operationId: a1.create_or_replace_policy_instance
+ - A1 Mediator
+ description: |
+ Create or replace a policy instance of type policy_type_id. The schema of the PUT body is defined by the create_schema field of the policy type.
+ operationId: a1_controller_create_or_replace_policy_instance
+ parameters:
+ - name: policy_type_id
+ in: path
+ description: |
+ represents a policy type identifier. Currently this is restricted to an integer range.
+ required: true
+ schema:
+ maximum: 2147483647
+ minimum: 1
+ type: integer
+ - name: policy_instance_id
+ in: path
+ description: |
+ represents a policy instance identifier. UUIDs are advisable but can be any string
+ required: true
+ schema:
+ type: string
+ - name: notificationDestination
+ in: query
+ description: |
+ URL send by non-RT RIC. This where non-RT RIC expects status updates on the policy creation
+ schema:
+ type: string
requestBody:
content:
application/json:
schema:
type: object
- description: >
- the schema of this object is defined by the create_schema field of the policy type
- example:
- enforce: true
- window_length: 10
- blocking_rate: 20
- trigger_threshold: 10
-
+ description: |
+ the schema of this object is defined by the create_schema field of the policy type
+ required: false
responses:
- '202':
- description: >
+ 202:
+ description: |
Policy instance creation initiated
- '400':
- description: >
+ content: {}
+ 400:
+ description: |
Bad PUT body for this policy instance
- '404':
- description: >
+ content: {}
+ 404:
+ description: |
There is no policy type with this policy_type_id
- '503':
- description: "Potentially transient backend database error. Client should attempt to retry later."
-
- '/a1-p/policytypes/{policy_type_id}/policies/{policy_instance_id}/status':
- parameters:
+ content: {}
+ 503:
+ description: Potentially transient backend database error. Client should
+ attempt to retry later.
+ content: {}
+ x-codegen-request-body-name: body
+ delete:
+ tags:
+ - A1 Mediator
+ description: |
+ Delete this policy instance
+ operationId: a1_controller_delete_policy_instance
+ parameters:
- name: policy_type_id
in: path
+ description: |
+ represents a policy type identifier. Currently this is restricted to an integer range.
required: true
schema:
- "$ref": "#/components/schemas/policy_type_id"
-
+ maximum: 2147483647
+ minimum: 1
+ type: integer
- name: policy_instance_id
in: path
+ description: |
+ represents a policy instance identifier. UUIDs are advisable but can be any string
required: true
schema:
- "$ref": "#/components/schemas/policy_instance_id"
-
- get:
- description: >
- Retrieve the policy instance status across all handlers of the policy
- If this endpoint returns successfully (200), it is either IN EFFECT or NOT IN EFFECT.
- IN EFFECT is returned if at least one policy handler in the RIC is implementing the policy
- NOT IN EFFECT is returned otherwise
- If a policy instance is successfully deleted, this endpoint will return a 404 (not a 200)
- tags:
- - A1 Mediator
- operationId: a1.get_policy_instance_status
+ type: string
+ - name: notificationDestination
+ in: query
+ description: |
+ URL send by non-RT RIC. This where non-RT RIC expects status updates on the policy creation
+ schema:
+ type: string
responses:
- '200':
- description: >
+ 202:
+ description: |
+ policy instance deletion initiated
+ content: {}
+ 404:
+ description: |
+ there is no policy instance with this policy_instance_id or there is no policy type with this policy_type_id
+ content: {}
+ 503:
+ description: Potentially transient backend database error. Client should
+ attempt to retry later.
+ content: {}
+ /a1-p/policytypes/{policy_type_id}/policies/{policy_instance_id}/status:
+ get:
+ tags:
+ - A1 Mediator
+ description: |
+ Retrieve the policy instance status across all handlers of the policy If this endpoint returns successfully (200),
+ it is either ENFORCED or NOT_ENFORCED. ENFORCED is returned if at least one policy handler in the RIC is implementing
+ the policy.
+ NOT_ENFORCED is returned otherwise If a policy instance is successfully deleted, this endpoint will return a 404 (not a 200).
+ operationId: a1_controller_get_policy_instance_status
+ parameters:
+ - name: policy_type_id
+ in: path
+ description: |
+ represents a policy type identifier. Currently this is restricted to an integer range.
+ required: true
+ schema:
+ maximum: 2147483647
+ minimum: 1
+ type: integer
+ - name: policy_instance_id
+ in: path
+ description: |
+ represents a policy instance identifier. UUIDs are advisable but can be any string
+ required: true
+ schema:
+ type: string
+ responses:
+ 200:
+ description: |
successfully retrieved the status
content:
application/json:
schema:
type: object
properties:
- instance_status:
+ enforceStatus:
type: string
enum:
- - IN EFFECT
- - NOT IN EFFECT
- has_been_deleted:
- type: boolean
- created_at:
+ - ENFORCED
+ - NOT_ENFORCED
+ enforceReason:
type: string
- format: date-time
-
- '404':
- description: >
+ enum:
+ - SCOPE_NOT_APPLICABLE
+ - STATEMENT_NOT_APPLICABLE
+ - OTHER_REASON
+ 404:
+ description: |
there is no policy instance with this policy_instance_id or there is no policy type with this policy_type_id
- '503':
- description: "Potentially transient backend database error. Client should attempt to retry later."
-
+ content: {}
+ 503:
+ description: Potentially transient backend database error. Client should
+ attempt to retry later.
+ content: {}
+ /data-delivery:
+ post:
+ tags:
+ - A1 EI Data Delivery
+ description: |
+ Deliver data produced by data producer.
+ operationId: a1_controller_data_delivery
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ description: |
+ object to represent data object
+ required: false
+ responses:
+ 200:
+ description: |
+ successfully delivered data from data producer
+ content: {}
+ 404:
+ description: |
+ no job id defined for this data delivery
+ content: {}
+ x-codegen-request-body-name: body
components:
schemas:
policy_type_schema:
- type: object
required:
- - name
- - description
- - policy_type_id
- create_schema
- additionalProperties: false
+ - description
+ - name
+ - policy_type_id
+ type: object
properties:
name:
type: string
@@ -328,22 +427,22 @@
type: string
description: description of the policy type
policy_type_id:
- description: the integer of the policy type
type: integer
+ description: the integer of the policy type
create_schema:
type: object
- description: >
+ properties: {}
+ description: |
jsonschema (following http://json-schema.org/draft-07/schema) of the CREATE payload to be sent to handlers of this policy
-
policy_type_id:
- description: >
- represents a policy type identifier. Currently this is restricted to an integer range.
- type: integer
- minimum: 1
maximum: 2147483647
-
+ minimum: 1
+ type: integer
+ description: |
+ represents a policy type identifier. Currently this is restricted to an integer range.
policy_instance_id:
- description: >
- represents a policy instance identifier. UUIDs are advisable but can be any string
type: string
- example: "3d2157af-6a8f-4a7c-810f-38c2f824bf12"
+ description: |
+ represents a policy instance identifier. UUIDs are advisable but can be any string
+ example: 3d2157af-6a8f-4a7c-810f-38c2f824bf12
+x-components: {}
diff --git a/near-rt-ric-simulator/src/OSC_2.1.0/__init__.py b/near-rt-ric-simulator/src/OSC_2.1.0/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/near-rt-ric-simulator/src/OSC_2.1.0/__init__.py
diff --git a/near-rt-ric-simulator/src/OSC_2.1.0/controllers/__init__.py b/near-rt-ric-simulator/src/OSC_2.1.0/controllers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/near-rt-ric-simulator/src/OSC_2.1.0/controllers/__init__.py
diff --git a/near-rt-ric-simulator/src/OSC_2.1.0/a1.py b/near-rt-ric-simulator/src/OSC_2.1.0/controllers/a1_mediator_controller.py
similarity index 78%
rename from near-rt-ric-simulator/src/OSC_2.1.0/a1.py
rename to near-rt-ric-simulator/src/OSC_2.1.0/controllers/a1_mediator_controller.py
index b343e30..aec84c5 100644
--- a/near-rt-ric-simulator/src/OSC_2.1.0/a1.py
+++ b/near-rt-ric-simulator/src/OSC_2.1.0/controllers/a1_mediator_controller.py
@@ -1,5 +1,5 @@
# ============LICENSE_START===============================================
-# Copyright (C) 2021 Nordix Foundation. All rights reserved.
+# Copyright (C) 2021-2023 Nordix Foundation. All rights reserved.
# ========================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -16,21 +16,20 @@
#
import json
-import datetime
+# import datetime
import time
from datetime import datetime
-from connexion import NoContent
-from flask import Flask, request, Response
+from flask import request, Response
from jsonschema import validate
-from var_declaration import policy_instances, policy_types, policy_status, policy_fingerprint, forced_settings, hosts_set
+from var_declaration import policy_instances, policy_types, policy_status, policy_fingerprint, callbacks, forced_settings, hosts_set, jobs, data_delivery
+from models.enforceStatus import EnforceStatus
from utils import calcFingerprint
from maincommon import extract_host_name, is_duplicate_check
from payload_logging import is_payload_logging
-#Constsants
-APPL_JSON='application/json'
-
+# Constants
+APPL_JSON = 'application/json'
#Helper funtion to log http reponse
def log_resp_text(msg):
@@ -40,7 +39,7 @@
print(str(msg))
# API Function: Health check
-def get_healthcheck():
+def a1_controller_get_healthcheck():
extract_host_name(hosts_set, request)
@@ -50,8 +49,7 @@
return (None, 200)
# API Function: Get all policy type ids
-def get_all_policy_types():
-
+def a1_controller_get_all_policy_types():
extract_host_name(hosts_set, request)
if ((r := check_modified_response()) is not None):
@@ -62,8 +60,7 @@
return (res, 200)
# API Function: Get a policy type
-def get_policy_type(policy_type_id):
-
+def a1_controller_get_policy_type(policy_type_id):
extract_host_name(hosts_set, request)
if ((r := check_modified_response()) is not None):
@@ -78,7 +75,7 @@
return Response(json.dumps(policy_types[policy_type_id]), 200, mimetype=APPL_JSON)
# API Function: Delete a policy type
-def delete_policy_type(policy_type_id):
+def a1_controller_delete_policy_type(policy_type_id):
extract_host_name(hosts_set, request)
@@ -102,7 +99,7 @@
# API Function: Create a policy type
-def create_policy_type(policy_type_id):
+def a1_controller_create_policy_type(policy_type_id):
extract_host_name(hosts_set, request)
@@ -141,7 +138,7 @@
# API Function: Get all policy ids for a type
-def get_all_policy_identities(policy_type_id):
+def a1_controller_get_all_instances_for_type(policy_type_id):
extract_host_name(hosts_set, request)
@@ -156,7 +153,7 @@
return (list(policy_instances[policy_type_id].keys()), 200)
# API Function: Get a policy instance
-def get_policy_instance(policy_type_id, policy_instance_id):
+def a1_controller_get_policy_instance(policy_type_id, policy_instance_id):
extract_host_name(hosts_set, request)
@@ -176,7 +173,7 @@
return Response(json.dumps(policy_instances[policy_type_id][policy_instance_id]), 200, mimetype=APPL_JSON)
# API function: Delete a policy
-def delete_policy_instance(policy_type_id, policy_instance_id):
+def a1_controller_delete_policy_instance(policy_type_id, policy_instance_id):
extract_host_name(hosts_set, request)
@@ -201,11 +198,13 @@
del policy_fingerprint[fp_previous]
del policy_instances[policy_type_id][policy_instance_id]
del policy_status[policy_instance_id]
+ callbacks.pop(policy_instance_id)
return (None, 202)
+
# API function: Create/update a policy
-def create_or_replace_policy_instance(policy_type_id, policy_instance_id):
+def a1_controller_create_or_replace_policy_instance(policy_type_id, policy_instance_id):
extract_host_name(hosts_set, request)
@@ -243,33 +242,35 @@
log_resp_text("Policy id already exist for other type")
return (None, 400)
- if (is_duplicate_check()):
- fp=calcFingerprint(data, policy_type_id)
+ if is_duplicate_check():
+ fp = calcFingerprint(data, policy_type_id)
else:
- fp=policy_instance_id
+ fp = policy_instance_id
- if ((fp in policy_fingerprint.keys()) and is_duplicate_check()):
- p_id=policy_fingerprint[fp]
+ if (fp in policy_fingerprint.keys()) and is_duplicate_check():
+ p_id = policy_fingerprint[fp]
if (p_id != policy_instance_id):
log_resp_text("Policy json duplicate of other instance")
return (None, 400)
- if (fp_previous is not None):
+ if fp_previous is not None:
del policy_fingerprint[fp_previous]
policy_fingerprint[fp]=policy_instance_id
- policy_instances[policy_type_id][policy_instance_id]=data
- ps={}
- ps["instance_status"] = "NOT IN EFFECT"
- ps["has_been_deleted"] = "false"
- ps["created_at"] = str(datetime.now().strftime("%m/%d/%Y, %H:%M:%S"))
- policy_status[policy_instance_id]=ps
+ noti = request.args.get('notificationDestination')
+ callbacks[policy_instance_id] = noti
+ policy_instances[policy_type_id][policy_instance_id]=data
+
+ enforceStatus = EnforceStatus("NOT_ENFORCED", "OTHER_REASON")
+ policy_status[policy_instance_id] = enforceStatus.to_dict()
+
+ # return Response(json.dumps(data), 200, mimetype=APPL_JSON)
return (None, 202)
# API function: Get policy status
-def get_policy_instance_status(policy_type_id, policy_instance_id):
+def a1_controller_get_policy_instance_status(policy_type_id, policy_instance_id):
extract_host_name(hosts_set, request)
@@ -287,6 +288,27 @@
return Response(json.dumps(policy_status[policy_instance_id]), 200, mimetype=APPL_JSON)
+# API function: Receive a data delivery package
+def a1_controller_data_delivery():
+
+ extract_host_name(hosts_set, request)
+ if ((r := check_modified_response()) is not None):
+ return r
+
+ try:
+ data = request.data
+ data = json.loads(data)
+ job = data['job']
+ jobs.index(job)
+ except ValueError:
+ log_resp_text("no job id defined for this data delivery")
+ return (None, 404)
+ except Exception:
+ log_resp_text("The data is corrupt or missing.")
+ return (None, 400)
+ data_delivery.append(data)
+ return (None, 200) # Should A1 and the A1 Simulator return 201 for creating a new resource?
+
# Helper: Create a response object if forced http response code is set
def get_forced_response():
diff --git a/near-rt-ric-simulator/src/OSC_2.1.0/main.py b/near-rt-ric-simulator/src/OSC_2.1.0/main.py
index 18bc03b..736438e 100644
--- a/near-rt-ric-simulator/src/OSC_2.1.0/main.py
+++ b/near-rt-ric-simulator/src/OSC_2.1.0/main.py
@@ -1,5 +1,5 @@
# ============LICENSE_START===============================================
-# Copyright (C) 2021 Nordix Foundation. All rights reserved.
+# Copyright (C) 2021-2023 Nordix Foundation. All rights reserved.
# ========================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,32 +15,31 @@
# ============LICENSE_END=================================================
#
-import connexion
import json
import sys
import os
import requests
+from connexion.resolver import RelativeResolver
from pathlib import Path
-from flask import Flask, escape, request, Response, jsonify
-from jsonschema import validate
-from var_declaration import policy_instances, policy_types, policy_status, policy_fingerprint, forced_settings, hosts_set, app
-from maincommon import check_apipath, apipath, get_supported_interfaces_response, extract_host_name
+from flask import request, Response, jsonify
+from var_declaration import policy_instances, policy_types, policy_status, callbacks, policy_fingerprint, forced_settings, hosts_set, app, data_delivery
+from models.enforceStatus import EnforceStatus
+from maincommon import check_apipath, get_supported_interfaces_response
from time import sleep
-#Constants
-TEXT_PLAIN='text/plain'
+
+# Constants
+TEXT_PLAIN = 'text/plain'
+APPL_JSON = 'application/json'
check_apipath()
# app is created in var_declarations
-import payload_logging # app var need to be initialized
-
-#Check alive function
+# Check alive function
@app.route('/', methods=['GET'])
def test():
-
return Response("OK", 200, mimetype=TEXT_PLAIN)
@app.route('/ip', methods=['GET'])
@@ -53,17 +52,16 @@
#Return the current and all supported yamls for the this container
@app.route('/container_interfaces', methods=['GET'])
def container_interfaces():
-
return get_supported_interfaces_response()
#Delete all created instances and status
@app.route('/deleteinstances', methods=['POST'])
def deleteinstances():
-
for i in policy_instances.keys():
policy_instances[i]={}
policy_status.clear()
+ callbacks.clear()
forced_settings.clear()
forced_settings['code']=None
forced_settings['delay']=None
@@ -73,13 +71,14 @@
#Delete all - all reset
@app.route('/deleteall', methods=['POST'])
def deleteall():
-
policy_instances.clear()
policy_types.clear()
policy_status.clear()
+ callbacks.clear()
forced_settings['code']=None
forced_settings['delay']=None
policy_fingerprint.clear()
+ data_delivery.clear()
return Response("All policy instances and types deleted", 200, mimetype=TEXT_PLAIN)
#Load a policy type
@@ -138,7 +137,6 @@
# Get all policy type ids
@app.route('/policytypes', methods=['GET'])
def get_policytype_ids():
-
return (json.dumps(list(policy_instances.keys())), 200)
#Set force response for one A1 response
@@ -164,36 +162,40 @@
return Response("Force delay: " + str(forced_settings['delay']) + " sec set for all A1 responses", 200, mimetype=TEXT_PLAIN)
-#Set status and reason
-#/status?policyid=<policyid>&status=<status>[&deleted=<boolean>][&created_at=<timestamp>]
+# Set status and reason
+#/status?policyid=<policyid>&status=<status>[&reason=<reason>]
@app.route('/status', methods=['PUT'])
def setstatus():
policy_id=request.args.get('policyid')
if (policy_id is None):
return Response('Parameter <policyid> missing in request', status=400, mimetype=TEXT_PLAIN)
-
if policy_id not in policy_status.keys():
return Response('Policyid: '+policy_id+' not found.', status=404, mimetype=TEXT_PLAIN)
+
status=request.args.get('status')
if (status is None):
return Response('Parameter <status> missing in request', status=400, mimetype=TEXT_PLAIN)
- policy_status[policy_id]["instance_status"]=status
- msg = "Status set to "+status
- deleted_policy=request.args.get('deleted')
- if (deleted_policy is not None):
- policy_status[policy_id]["has_been_deleted"]=deleted_policy
- msg = msg + " and has_been_deleted set to "+deleted_policy
- created_at = request.args.get('created_at')
- if (created_at is not None):
- policy_status[policy_id]["created_at"]=created_at
- msg = msg + " and created_at set to "+created_at
- msg=msg + " for policy: " + policy_id
+
+ enforceStatus = EnforceStatus()
+ try:
+ enforceStatus.enforce_status = status
+ msg = "Status set to " + status
+
+ reason = request.args.get('reason')
+ if (reason is not None):
+ enforceStatus.enforce_reason = reason
+ msg = msg + " and " + reason
+
+ policy_status[policy_id] = enforceStatus.to_dict()
+ msg = msg + " for policy: " + policy_id
+ except ValueError as error:
+ return Response(str(error), status=400, mimetype=TEXT_PLAIN)
+
return Response(msg, 200, mimetype=TEXT_PLAIN)
-
-#Metrics function
-#Get a named counter
+# Metrics function
+# Get a named counter
@app.route('/counter/<string:countername>', methods=['GET'])
def getcounter(countername):
@@ -209,7 +211,8 @@
hosts=",".join(hosts_set)
return str(hosts),200
elif (countername == "datadelivery"):
- return Response(str(0),200, mimetype=TEXT_PLAIN)
+ data_delivery_counter = str(len(data_delivery))
+ return Response(data_delivery_counter,200, mimetype=TEXT_PLAIN)
else:
return Response("Counter name: "+countername+" not found.",404, mimetype=TEXT_PLAIN)
@@ -218,7 +221,49 @@
if isinstance(sys.argv[1], int):
port_number = sys.argv[1]
-app.add_api('openapi.yaml')
+
+# Send status
+# /sendstatus?policyid=<policyid>
+@app.route('/sendstatus', methods=['POST'])
+def sendstatus():
+ policyid = request.args.get('policyid')
+ if policyid is None:
+ return Response('Parameter <policyid> missing in request', status=400, mimetype=TEXT_PLAIN)
+ if policyid not in policy_status.keys():
+ return Response('Policyid: '+policyid+' not found.', status=404, mimetype=TEXT_PLAIN)
+
+ ps = policy_status[ policyid ]
+ cb_url = callbacks[ policyid ]
+
+ try:
+ resp = requests.post(cb_url, json = json.dumps(ps), headers = { "Content-Type": APPL_JSON, "Accept": "*/*" })
+ resp.raise_for_status()
+ if (resp.status_code >= 200 and resp.status_code <= 300):
+ return Response("OK", resp.status_code, mimetype = TEXT_PLAIN)
+ return Response('Post status failed', status = resp.status_code, mimetype = TEXT_PLAIN)
+
+ except requests.ConnectionError as error:
+ return Response('Post status failed with Connection Error, could not send to ' + str(cb_url), status = 502, mimetype = TEXT_PLAIN)
+ except requests.Timeout as error:
+ return Response('Post status failed with Timeout, could not send to ' + str(cb_url), status = 504, mimetype = TEXT_PLAIN)
+ except requests.HTTPError as error:
+ return Response('Post status failed with HTTP Error, could not send to ' + str(cb_url), status = 502, mimetype = TEXT_PLAIN)
+ except requests.RequestException as error:
+ return Response('Post status failed with RequestException, could not send to ' + str(cb_url), status = 500, mimetype = TEXT_PLAIN)
+
+# Receive status (only for testing callbacks)
+# /statustest
+@app.route('/statustest', methods=['POST', 'PUT'])
+def statustest():
+ try:
+ data = request.data
+ data = json.loads(data)
+ except Exception:
+ return Response("The status data is corrupt or missing.", 400, mimetype=TEXT_PLAIN)
+
+ return Response("OK", 201, mimetype=TEXT_PLAIN)
+
+app.add_api('openapi.yaml', resolver=RelativeResolver('controllers.a1_mediator_controller'))
if __name__ == '__main__':
- app.run(port=port_number, host="127.0.0.1", threaded=False)
\ No newline at end of file
+ app.run(port=port_number, host="127.0.0.1", threaded=True)
\ No newline at end of file
diff --git a/near-rt-ric-simulator/src/OSC_2.1.0/models/enforceStatus.py b/near-rt-ric-simulator/src/OSC_2.1.0/models/enforceStatus.py
new file mode 100644
index 0000000..89fafd9
--- /dev/null
+++ b/near-rt-ric-simulator/src/OSC_2.1.0/models/enforceStatus.py
@@ -0,0 +1,81 @@
+# coding: utf-8
+
+from __future__ import absolute_import
+from datetime import date, datetime # noqa: F401
+
+from typing import List, Dict # noqa: F401
+
+
+class EnforceStatus():
+
+ def __init__(self, enforce_status: str=None, enforce_reason: str=None): # noqa: E501
+ """EnforceStatus
+
+ :param enforce_status: The enforce_status of this EnforceStatus. # noqa: E501
+ :type enforce_status: str
+ :param enforce_reason: The enforce_reason of this EnforceStatus. # noqa: E501
+ :type enforce_reason: str
+ """
+ self._enforce_status = enforce_status
+ self._enforce_reason = enforce_reason
+
+ @property
+ def enforce_status(self) -> str:
+ """Gets the enforce_status of this EnforceStatus.
+
+ :return: The enforce_status of this EnforceStatus.
+ :rtype: str
+ """
+ return self._enforce_status
+
+ @enforce_status.setter
+ def enforce_status(self, enforce_status: str):
+ """Sets the enforce_status of this EnforceStatus.
+
+ :param enforce_status: The enforce_status of this EnforceStatus.
+ :type enforce_status: str
+ """
+ allowed_values = ["ENFORCED", "NOT_ENFORCED"] # noqa: E501
+ if enforce_status not in allowed_values:
+ raise ValueError(
+ "Invalid value for `enforce_status` ({0}), must be one of {1}"
+ .format(enforce_status, allowed_values)
+ )
+
+ self._enforce_status = enforce_status
+
+ @property
+ def enforce_reason(self) -> str:
+ """Gets the enforce_reason of this EnforceStatus.
+
+ :return: The enforce_reason of this EnforceStatus.
+ :rtype: str
+ """
+ return self._enforce_reason
+
+ @enforce_reason.setter
+ def enforce_reason(self, enforce_reason: str):
+ """Sets the enforce_reason of this EnforceStatus.
+
+ :param enforce_reason: The enforce_reason of this EnforceStatus.
+ :type enforce_reason: str
+ """
+ allowed_values = ["SCOPE_NOT_APPLICABLE", "STATEMENT_NOT_APPLICABLE", "OTHER_REASON"] # noqa: E501
+ if enforce_reason not in allowed_values:
+ raise ValueError(
+ "Invalid value for `enforce_reason` ({0}), must be one of {1}"
+ .format(enforce_reason, allowed_values)
+ )
+
+ self._enforce_reason = enforce_reason
+
+ def to_dict(self):
+ """Returns the model properties as a dict
+
+ :rtype: dict
+ """
+ result = {
+ 'enforceStatus': self._enforce_status,
+ 'enforceReason': self._enforce_reason
+ }
+ return result
diff --git a/near-rt-ric-simulator/src/OSC_2.1.0/var_declaration.py b/near-rt-ric-simulator/src/OSC_2.1.0/var_declaration.py
index f4ff6ac..f78ca50 100644
--- a/near-rt-ric-simulator/src/OSC_2.1.0/var_declaration.py
+++ b/near-rt-ric-simulator/src/OSC_2.1.0/var_declaration.py
@@ -1,5 +1,5 @@
# ============LICENSE_START===============================================
-# Copyright (C) 2021 Nordix Foundation. All rights reserved.
+# Copyright (C) 2021-2023 Nordix Foundation. All rights reserved.
# ========================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,14 +18,22 @@
from maincommon import apipath
import connexion
-#Main app
-app = connexion.FlaskApp(__name__, specification_dir=apipath)
+# Main app
+def create_app():
+ app = connexion.FlaskApp(__name__, specification_dir=apipath)
+ return app
-policy_types={}
-policy_instances={}
-policy_status={}
-forced_settings={}
-forced_settings['code']=None
-forced_settings['delay']=None
-policy_fingerprint={}
-hosts_set=set()
+app = create_app()
+
+policy_types = {}
+policy_instances = {}
+policy_status = {}
+callbacks = {}
+forced_settings = {}
+forced_settings['code'] = None
+forced_settings['delay'] = None
+policy_fingerprint = {}
+hosts_set = set()
+
+data_delivery = []
+jobs = ['100', '101']
diff --git a/near-rt-ric-simulator/src/STD_2.0.0/main.py b/near-rt-ric-simulator/src/STD_2.0.0/main.py
index 16e4a31..9733a0f 100644
--- a/near-rt-ric-simulator/src/STD_2.0.0/main.py
+++ b/near-rt-ric-simulator/src/STD_2.0.0/main.py
@@ -28,8 +28,10 @@
from var_declaration import policy_instances, policy_types, policy_status, callbacks, forced_settings, policy_fingerprint, hosts_set, data_delivery_counter, app
from maincommon import check_apipath, apipath, get_supported_interfaces_response, extract_host_name
-#Constants
+# Constants
TEXT_PLAIN='text/plain'
+APPL_JSON='application/json'
+
check_apipath()
@@ -198,7 +200,7 @@
return Response('Post status failed with code: '+resp.status_code, status=500, mimetype=TEXT_PLAIN)
data = resp.json()
- return Response(data, 200, mimetype='application/json')
+ return Response(data, 200, mimetype=APPL_JSON)
#Receive status (only for testing callbacks)
#/statustest
@@ -210,7 +212,7 @@
except Exception:
return Response("The status data is corrupt or missing.", 400, mimetype=TEXT_PLAIN)
- return Response(json.dumps(data), 200, mimetype='application/json')
+ return Response(json.dumps(data), 200, mimetype=APPL_JSON)
#Receive a data delivery package
#/datadelivery
diff --git a/near-rt-ric-simulator/src/common/maincommon.py b/near-rt-ric-simulator/src/common/maincommon.py
index 131bf0d..6239f79 100644
--- a/near-rt-ric-simulator/src/common/maincommon.py
+++ b/near-rt-ric-simulator/src/common/maincommon.py
@@ -22,9 +22,9 @@
import socket
import ssl
-#Must exist
+# Must exist
apipath=os.environ['APIPATH']
-#May exist
+# May exist
remote_hosts_logging=os.getenv('REMOTE_HOSTS_LOGGING')
duplicate_check=os.getenv('DUPLICATE_CHECK')
diff --git a/near-rt-ric-simulator/src/start.sh b/near-rt-ric-simulator/src/start.sh
index 8518541..ad5c677 100755
--- a/near-rt-ric-simulator/src/start.sh
+++ b/near-rt-ric-simulator/src/start.sh
@@ -25,27 +25,27 @@
fi
echo "Version folder for simulator: "$1
-#Set path to open api
+# Set path to open api
export APIPATH=$PWD/api/$1
echo "APIPATH set to: "$APIPATH
cd src
-#Include common module(s)
+# Include common module(s)
export PYTHONPATH=$PWD/common
echo "PYTHONPATH set to: "$PYTHONPATH
cd $1
-#start nginx
+# start nginx
nginx -c /usr/src/app/nginx.conf
-#start callBack server
+start callBack server
if [[ ${A1_VERSION} == "STD"* ]]; then
echo "Path to callBack.py: "$PWD
python -u callBack.py &
fi
-#start near-rt-ric-simulator
+# start near-rt-ric-simulator
echo "Path to main.py: "$PWD
python -u main.py
diff --git a/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh b/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh
index 2f70295..f97d945 100755
--- a/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh
+++ b/near-rt-ric-simulator/test/OSC_2.1.0/basic_test.sh
@@ -115,11 +115,16 @@
echo "=== API: Create policy instance pi1 of type: 1 ==="
RESULT=""
+# res=$(cat jsonfiles/pi1.json)
+# RESULT="json:$res"
do_curl PUT '/a1-p/policytypes/1/policies/pi1' 202 jsonfiles/pi1.json
echo "=== API: Update policy instance pi1 of type: 1 ==="
RESULT=""
do_curl PUT '/a1-p/policytypes/1/policies/pi1' 202 jsonfiles/pi1.json
+# res=$(cat jsonfiles/pi1.json)
+# RESULT="json:$res"
+# do_curl PUT '/a1-p/policytypes/1/policies/pi1' 200 jsonfiles/pi1.json
echo "=== API: Load a policy type: 1, shall fail ==="
RESULT=""
@@ -137,6 +142,9 @@
echo "=== API: Create policy instance pi2 (copy of pi1) of type: 1. Shall succeed ==="
RESULT=""
do_curl PUT '/a1-p/policytypes/1/policies/pi2' 202 jsonfiles/pi1.json
+ # res=$(cat jsonfiles/pi1.json)
+ # RESULT="json:$res"
+ # do_curl PUT '/a1-p/policytypes/1/policies/pi2' 200 jsonfiles/pi1.json
echo "=== Delete policy instance: pi2 ==="
RESULT=""
@@ -152,7 +160,7 @@
do_curl GET '/a1-p/policytypes/1' 401
echo "=== API: Get policy status ==="
-RESULT="json:{\"instance_status\": \"NOT IN EFFECT\", \"has_been_deleted\": \"false\", \"created_at\": \"????\"}"
+RESULT="json:{\"enforceStatus\": \"NOT_ENFORCED\", \"enforceReason\": \"OTHER_REASON\"}"
do_curl GET '/a1-p/policytypes/1/policies/pi1/status' 200
echo "=== Load a policy type: 2 ==="
@@ -206,11 +214,22 @@
echo "=== API: Create policy instance pi2 of type: 2 ==="
RESULT=""
do_curl PUT '/a1-p/policytypes/2/policies/pi2' 202 jsonfiles/pi2.json
+# res=$(cat jsonfiles/pi2.json)
+# RESULT="json:$res"
+# do_curl PUT '/a1-p/policytypes/2/policies/pi2' 200 jsonfiles/pi2.json
echo "=== API: Update policy instance pi2 of type: 2 ==="
RESULT=""
do_curl PUT '/a1-p/policytypes/2/policies/pi2' 202 jsonfiles/pi2.json
+echo "=== API: Update policy instance pi2 of type: 2 ==="
+RESULT=""
+do_curl PUT "/a1-p/policytypes/2/policies/pi2?notificationDestination=http://localhost:${PORT}/statustest" 202 jsonfiles/pi2.json
+
+echo "=== Send status for pi2==="
+RESULT="OK"
+do_curl POST '/sendstatus?policyid=pi2' 201 jsonfiles/pi2.json
+
echo "=== API: Get instances for type 1, shall contain pi1 ==="
RESULT="json:[ \"pi1\" ]"
do_curl GET '/a1-p/policytypes/1/policies' jsonfiles/200
@@ -227,6 +246,9 @@
echo "=== API: Create policy instance pi11 (copy of pi1) of type: 1. Shall succeed ==="
RESULT=""
do_curl PUT '/a1-p/policytypes/1/policies/pi11' 202 jsonfiles/pi1.json
+ # res=$(cat jsonfiles/pi1.json)
+ # RESULT="json:$res"
+ # do_curl PUT '/a1-p/policytypes/1/policies/pi11' 200 jsonfiles/pi1.json
echo "=== Delete policy instance: pi11 ==="
RESULT=""
@@ -241,13 +263,15 @@
echo "=== API: Create policy instance pi3 (copy of pi1) of type: 1. Shall succeed ==="
RESULT=""
do_curl PUT '/a1-p/policytypes/1/policies/pi3' 202 jsonfiles/pi1.json
+ # res=$(cat jsonfiles/pi1.json)
+ # RESULT="json:$res"
+ # do_curl PUT '/a1-p/policytypes/1/policies/pi3' 200 jsonfiles/pi1.json
echo "=== Delete policy instance: pi3 ==="
RESULT=""
do_curl DELETE '/a1-p/policytypes/1/policies/pi3' 202
fi
-
echo "=== API: Get instances for type 1, shall contain pi1 ==="
RESULT="json:[ \"pi1\" ]"
do_curl GET '/a1-p/policytypes/1/policies' jsonfiles/200
@@ -256,8 +280,6 @@
RESULT="json:[ \"pi2\" ]"
do_curl GET '/a1-p/policytypes/2/policies' 200
-
-
echo "=== Set force response code 401. ==="
RESULT="*"
do_curl POST '/forceresponse?code=401' 200
@@ -271,7 +293,7 @@
do_curl POST '/forcedelay?delay=10' 200
echo "=== API: Get policy status for pi1. Shall delay 10 sec ==="
-RESULT="json:{\"instance_status\": \"NOT IN EFFECT\", \"has_been_deleted\": \"false\", \"created_at\": \"????\"}"
+RESULT="json:{\"enforceStatus\": \"NOT_ENFORCED\", \"enforceReason\": \"OTHER_REASON\"}"
do_curl GET '/a1-p/policytypes/1/policies/pi1/status' 200
echo "=== Reset force delay. ==="
@@ -279,19 +301,19 @@
do_curl POST '/forcedelay' 200
echo "=== Set status for pi1 ==="
-RESULT="Status set to IN EFFECT for policy: pi1"
-do_curl PUT '/status?policyid=pi1&status=IN%20EFFECT' 200
+RESULT="Status set to ENFORCED for policy: pi1"
+do_curl PUT '/status?policyid=pi1&status=ENFORCED' 200
echo "=== API: Get policy status for pi1 ==="
-RESULT="json:{\"instance_status\": \"IN EFFECT\", \"has_been_deleted\": \"false\", \"created_at\": \"????\"}"
+RESULT="json:{\"enforceStatus\": \"ENFORCED\", \"enforceReason\": null}"
do_curl GET '/a1-p/policytypes/1/policies/pi1/status' 200
echo "=== Set status for pi1 ==="
-RESULT="Status set to IN EFFECT and has_been_deleted set to true and created_at set to 2020-03-30 12:00:00 for policy: pi1"
-do_curl PUT '/status?policyid=pi1&status=IN%20EFFECT&deleted=true&created_at=2020-03-30%2012:00:00' 200
+RESULT="Status set to ENFORCED for policy: pi1"
+do_curl PUT '/status?policyid=pi1&status=ENFORCED' 200
echo "=== API: Get policy status for pi1 ==="
-RESULT="json:{\"instance_status\": \"IN EFFECT\", \"has_been_deleted\": \"true\", \"created_at\": \"2020-03-30 12:00:00\"}"
+RESULT="json:{\"enforceStatus\": \"ENFORCED\", \"enforceReason\": null}"
do_curl GET '/a1-p/policytypes/1/policies/pi1/status' 200
echo "=== Get counter: instances ==="
@@ -326,6 +348,10 @@
RESULT="1"
do_curl GET /counter/num_instances 200
+echo "=== Get counter: datadelivery ==="
+RESULT="0"
+do_curl GET /counter/datadelivery 200
+
echo "********************"
echo "*** All tests ok ***"
echo "********************"
diff --git a/near-rt-ric-simulator/tests/test_osc_2_1_0.py b/near-rt-ric-simulator/tests/test_osc_2_1_0.py
index deff757..5c9b780 100644
--- a/near-rt-ric-simulator/tests/test_osc_2_1_0.py
+++ b/near-rt-ric-simulator/tests/test_osc_2_1_0.py
@@ -1,5 +1,5 @@
# ============LICENSE_START===============================================
-# Copyright (C) 2021 Nordix Foundation. All rights reserved.
+# Copyright (C) 2021-2023 Nordix Foundation. All rights reserved.
# ========================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,19 +15,59 @@
# ============LICENSE_END=================================================
#
-# This test case test the OSC_2.1.0 version of the simulator
+# This test case tests the OSC_2.1.0 version of the simulator
-import json
-#Version of simulator
+# Version of simulator
INTERFACE_VERSION="OSC_2.1.0"
-from unittest_setup import SERVER_URL, setup_env, get_testdata_dir, client
+import json
+import pytest
+import requests
+import threading
+from unittest_setup import SERVER_URL, PORT_NUMBER, setup_env, get_testdata_dir, client
+# from unittest_setup import run_flask_app
-#Setup env and import paths
+# Setup env and import paths
setup_env(INTERFACE_VERSION)
from compare_json import compare
+from models.enforceStatus import EnforceStatus
+
+def test_enforce_reason(client):
+ """
+ Test that we can set a valid enforce status and reason, and that we reject invalid cases.
+ """
+ enforceStatus = EnforceStatus()
+
+ enforceStatus.enforce_status = 'NOT_ENFORCED'
+ enforceStatus.enforce_reason = 'SCOPE_NOT_APPLICABLE'
+ enforce_dict = enforceStatus.to_dict()
+ assert enforce_dict['enforceStatus'] == 'NOT_ENFORCED'
+ assert enforce_dict['enforceReason'] == 'SCOPE_NOT_APPLICABLE'
+
+ enforceStatus.enforce_status = 'ENFORCED'
+ enforceStatus.enforce_reason = 'STATEMENT_NOT_APPLICABLE'
+ enforce_dict = enforceStatus.to_dict()
+ assert enforce_dict['enforceStatus'] == 'ENFORCED'
+ assert enforce_dict['enforceReason'] == 'STATEMENT_NOT_APPLICABLE'
+
+ enforceStatus.enforce_reason = 'OTHER_REASON'
+ enforce_dict = enforceStatus.to_dict()
+ assert enforce_dict['enforceReason'] == 'OTHER_REASON'
+
+ enforce_status = enforceStatus.enforce_status
+ assert str(enforce_status) == 'ENFORCED'
+
+ enforce_reason = enforceStatus.enforce_reason
+ assert str(enforce_reason) == 'OTHER_REASON'
+
+ with pytest.raises(ValueError):
+ enforceStatus.enforce_status = 'ERROR'
+
+ with pytest.raises(ValueError):
+ enforceStatus.enforce_reason = 'ERROR'
+
def test_apis(client):
@@ -176,9 +216,8 @@
# API: Get policy status
policy_status = {
- "instance_status" : "NOT IN EFFECT",
- "has_been_deleted" : "false",
- "created_at" : "????"
+ "enforceStatus" : "NOT_ENFORCED",
+ "enforceReason" : "OTHER_REASON",
}
response=client.get(SERVER_URL+'a1-p/policytypes/1/policies/pi1/status')
assert response.status_code == 200
@@ -315,9 +354,8 @@
# API: Get policy status for pi1. Shall delay 10 sec
policy_status = {
- "instance_status" : "NOT IN EFFECT",
- "has_been_deleted" : "false",
- "created_at" : "????"
+ "enforceStatus" : "NOT_ENFORCED",
+ "enforceReason" : "OTHER_REASON",
}
response=client.get(SERVER_URL+'a1-p/policytypes/1/policies/pi1/status')
assert response.status_code == 200
@@ -331,14 +369,13 @@
assert response.data == b"Force delay: None sec set for all A1 responses"
# Set status for pi1
- response=client.put(SERVER_URL+'status?policyid=pi1&status=IN%20EFFECT')
+ response=client.put(SERVER_URL+'status?policyid=pi1&status=ENFORCED')
assert response.status_code == 200
# API: Get policy status for pi1
policy_status = {
- "instance_status" : "IN EFFECT",
- "has_been_deleted" : "false",
- "created_at" : "????"
+ "enforceStatus" : "ENFORCED",
+ "enforceReason" : None,
}
response=client.get(SERVER_URL+'a1-p/policytypes/1/policies/pi1/status')
assert response.status_code == 200
@@ -347,14 +384,13 @@
assert res == True
# Set status for pi1
- response=client.put(SERVER_URL+'status?policyid=pi1&status=IN%20EFFECT&deleted=true&created_at=2020-03-30%2012:00:00')
+ response=client.put(SERVER_URL+'status?policyid=pi1&status=NOT_ENFORCED&reason=SCOPE_NOT_APPLICABLE')
assert response.status_code == 200
# API: Get policy status for pi1
policy_status = {
- "instance_status" : "IN EFFECT",
- "has_been_deleted" : "true",
- "created_at" : "????"
+ "enforceStatus" : "NOT_ENFORCED",
+ "enforceReason" : "SCOPE_NOT_APPLICABLE",
}
response=client.get(SERVER_URL+'a1-p/policytypes/1/policies/pi1/status')
assert response.status_code == 200
@@ -362,7 +398,7 @@
res=compare(policy_status, result)
assert res == True
- # Get counter: intstance
+ # Get counter: num_instances
response=client.get(SERVER_URL+'counter/num_instances')
assert response.status_code == 200
assert response.data == b"2"
@@ -495,14 +531,108 @@
response=client.get(SERVER_URL+'a1-p/policytypes/1/policies/pi111/status')
assert response.status_code == 404
- # Load policy type, no type in url - shall faill
+ # Load policy type, no type in url - shall fail
with open(testdata+'pt2.json') as json_file:
policytype_2 = json.load(json_file)
response=client.put(SERVER_URL+'policytype', headers=header, data=json.dumps(policytype_2))
assert response.status_code == 400
- # Load policy type - duplicatee - shall faill
+ # Load policy type - duplicatee - shall fail
with open(testdata+'pt1.json') as json_file:
policytype_1 = json.load(json_file)
response=client.put(SERVER_URL+'policytype?id=2', headers=header, data=json.dumps(policytype_1))
assert response.status_code == 400
+
+ # Get counter: data_delivery
+ response=client.get(SERVER_URL+'counter/datadelivery')
+ assert response.status_code == 200
+ assert response.data == b"0"
+
+ # Send data to data-delivery with empty payload
+ json_payload={}
+ response=client.post(SERVER_URL+'data-delivery', headers=header, data=json.dumps(json_payload))
+ assert response.status_code == 400
+
+ # Send invalid data to data-delivery
+ json_payload={
+ "job":"200",
+ "payload":"payload"
+ }
+ response=client.post(SERVER_URL+'data-delivery', headers=header, data=json.dumps(json_payload))
+ assert response.status_code == 404
+
+ # Send data to data-delivery with valid job
+ json_payload={
+ "job":"100",
+ "payload":"payload"
+ }
+ response=client.post(SERVER_URL+'data-delivery', headers=header, data=json.dumps(json_payload))
+ assert response.status_code == 200
+
+ # Send data to data-delivery with valid job
+ json_payload={
+ "job":"101",
+ "payload":"another payload"
+ }
+ response=client.post(SERVER_URL+'data-delivery', headers=header, data=json.dumps(json_payload))
+ assert response.status_code == 200
+
+ # Get counter: data_delivery
+ response=client.get(SERVER_URL+'counter/datadelivery')
+ assert response.status_code == 200
+ assert response.data == b"2"
+
+
+def test_notificationDestination(client):
+ testdata=get_testdata_dir()
+ # Header for json payload
+ header = {
+ "Content-Type" : "application/json"
+ }
+
+ # === API: Update policy instance pi2 of type: 2 ==="
+ with open(testdata+'pi2.json') as json_file:
+ policytype_2 = json.load(json_file)
+ response = client.put(SERVER_URL+"a1-p/policytypes/2/policies/pi2?notificationDestination=http://localhost:8085/statustest", headers=header, data=json.dumps(policytype_2))
+ assert response.status_code == 202
+ result = response.data
+ assert result == b""
+
+# def test_sendstatus(client):
+# testdata=get_testdata_dir()
+# # Header for json payload
+# header = {
+# "Content-Type" : "application/json"
+# }
+
+# # === Send status for pi2==="
+# with open(testdata+'pi2.json') as json_file:
+# policytype_2 = json.load(json_file)
+# response = client.post(SERVER_URL+'sendstatus?policyid=pi2', headers=header, data=json.dumps(policytype_2))
+# assert response.status_code == 201
+# result = response.data
+# assert result == b"OK"
+
+
+# def test_multithreaded(client):
+# # Create a new thread to run the Flask app
+# app_thread = threading.Thread(target=run_flask_app)
+# app_thread.start()
+
+# # Perform your tests here
+# testdata=get_testdata_dir()
+# # Header for json payload
+# header = {
+# "Content-Type" : "application/json"
+# }
+
+# # === Send status for pi2==="
+# with open(testdata+'pi2.json') as json_file:
+# policytype_2 = json.load(json_file)
+# response = client.post(SERVER_URL+'sendstatus?policyid=pi2', headers=header, data=json.dumps(policytype_2))
+# assert response.status_code == 201
+# result = response.data
+# assert result == b"OK"
+
+# # Wait for the Flask app thread to finish
+# app_thread.join()
diff --git a/near-rt-ric-simulator/tests/unittest_setup.py b/near-rt-ric-simulator/tests/unittest_setup.py
index 9ffd009..06567cf 100644
--- a/near-rt-ric-simulator/tests/unittest_setup.py
+++ b/near-rt-ric-simulator/tests/unittest_setup.py
@@ -25,7 +25,7 @@
HOST_IP="localhost"
SERVER_URL="http://"+HOST_IP+":"+PORT_NUMBER+"/"
-#Dir for json test data files
+# Dir for json test data files
testdata=""
def setup_env(interface_version):
@@ -51,9 +51,14 @@
def get_testdata_dir():
return testdata
-#Test client for rest calls
+# Test client for rest calls
@pytest.fixture
def client():
from main import app
- with app.app.test_client() as c:
- yield c
\ No newline at end of file
+ with app.app.test_client() as client:
+ yield client
+
+# # Run the Flask app in a separate thread for testing
+# def run_flask_app():
+# from main import app
+# app.app.run(port=8085, host="127.0.0.1", threaded=True)