from flask import Response
import connexion
import json
+from jsonschema.exceptions import ValidationError
from a1 import get_module_logger
from a1 import a1rmr, exceptions, utils
"""
try:
return func()
+ except ValidationError as exc:
+ logger.exception(exc)
+ return "", 400
except exceptions.PolicyNotFound as exc:
logger.exception(exc)
return "", 404
# The Jenkins job uses this string for the tag in the image name
# for example nexus3.o-ran-sc.org:10004/my-image-name:my-tag
---
-tag: 0.8.3
+tag: 0.8.4
Unit Testing
============
-Note, this requires rmr to be installed on the system executing the tests. Also, this requires the python packages ``tox`` and ``pytest``.
+Note, before this will work, for the first time on the machine running the tests, run ``./install_deps.sh``. This is only needed once on the machine.
+Also, this requires the python packages ``tox`` and ``pytest``.
::
Running locally
===============
-1. This requires that RMR is installed on the base system. (the
- Dockerfile does this when running in Docker)
+1. Before this will work, for the first time on that machine, run ``./install_deps.sh``
2. It also requires rmr-python >= 0.10.1 installed. (The dockerfile also
does this)
::
curl -v -X PUT -H "Content-Type: application/json" -d '{}' localhost:10000/ric/policies/test_policy
- curl -v -X PUT -H "Content-Type: application/json" -d '{"dc_admission_start_time": "10:00:00", "dc_admission_end_time": "11:00:00"}' localhost:10000/ric/policies/control_admission_time
+ curl -v -X PUT -H "Content-Type: application/json" -d '{ "enforce":true, "window_length":10, "blocking_rate":20, "trigger_threshold":10 }' localhost:10000/ric/policies/admission_control_policy
Finally, there is a test “bombarder” that will flood A1 with messages
with good message types but bad transaction IDs, to test A1’s resilience
and this project adheres to `Semantic
Versioning <http://semver.org/>`__.
+[0.8.4] - 7/16/2019
+-------------------
+
+::
+
+ * Fix the 400, which was in the API, but wasn't actually implemented
+ * Update the test fixture manifests to reflect the latest adm control, paves way for next feature coming which is a policy GET
+
+
+
[0.8.3] - 6/18/2019
-------------------
--- /dev/null
+#!/bin/sh
+git clone https://gerrit.oran-osc.org/r/ric-plt/lib/rmr \
+ && cd rmr \
+ && mkdir .build; cd .build; cmake .. -DPACK_EXTERNALS=1; sudo make install \
+ && cd ../.. \
+ && rm -rf rmr
apiVersion: v1
description: A1 Helm chart for Kubernetes
name: a1mediator
-version: 0.8.3
+version: 0.8.4
{
"controls":[
{
- "name":"control_admission_time",
- "description":"time period to allow dual connection",
- "message_receives_rmr_type":"DC_ADMISSION_INTERVAL_CONTROL",
+ "name":"admission_control_policy",
+ "description":"various parameters to control admission of dual connection",
+ "control_state_request_rmr_type":"DC_ADM_GET_POLICY",
+ "control_state_request_reply_rmr_type":"DC_ADM_GET_POLICY_ACK",
+ "message_receives_rmr_type":"DC_ADM_INT_CONTROL",
"message_receives_payload_schema":{
"$schema":"http://json-schema.org/draft-07/schema#",
"type":"object",
"properties":{
- "dc_admission_start_time":{
- "type":"string",
- "pattern":"^[0-9]{2}:[0-9]{2}:[0-9]{2}$"
+ "enforce":{
+ "type":"boolean",
+ "default":true
},
- "dc_admission_end_time":{
- "type":"string",
- "pattern":"^[0-9]{2}:[0-9]{2}:[0-9]{2}$"
+ "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"
}
},
- "required":[
- "dc_admission_start_time",
- "dc_admission_end_time"
- ]
+ "additionalProperties":false
},
- "message_sends_rmr_type":"DC_ADMISSION_INTERVAL_CONTROL_ACK",
+ "message_sends_rmr_type":"DC_ADM_INT_CONTROL_ACK",
"message_sends_payload_schema":{
"$schema":"http://json-schema.org/draft-07/schema#",
"type":"object",
"message":{
"type":"string"
}
- }
+ },
+ "required":[
+ "status"
+ ],
+ "additionalProperties":false
}
},
{
-DC_ADMISSION_INTERVAL_CONTROL:20000
-DC_ADMISSION_INTERVAL_CONTROL_ACK:20001
+DC_ADM_INT_CONTROL:20000
+DC_ADM_INT_CONTROL_ACK:20001
TEST_REQ:10000
TEST_ACK:10001
-{"dc_admission_start_time": "10:00:00", "dc_admission_end_time": "11:00:00"}
+{
+ "enforce":true,
+ "window_length":10,
+ "blocking_rate":20,
+ "trigger_threshold":10
+}
stages:
- name: test the admission control policy
request:
- url: http://localhost:10000/ric/policies/control_admission_time
+ url: http://localhost:10000/ric/policies/admission_control_policy
method: PUT
json:
- dc_admission_start_time: "10:00:00"
- dc_admission_end_time: "11:00:00"
+ enforce: true
+ window_length: 10
+ blocking_rate: 20
+ trigger_threshold: 10
headers:
content-type: application/json
response:
response:
status_code: 404
+ - name: bad body for admission control policy
+ request:
+ url: http://localhost:10000/ric/policies/admission_control_policy
+ method: PUT
+ json:
+ not: "expected"
+ headers:
+ content-type: application/json
+ response:
+ status_code: 400
+
- name: not a json
request:
- url: http://localhost:10000/ric/policies/control_admission_time
+ url: http://localhost:10000/ric/policies/admission_control_policy
method: PUT
data: "asdf"
response:
status_code: 415
- - name: body not expected
+ - name: bad body for test policy
request:
url: http://localhost:10000/ric/policies/test_policy
method: PUT
setup(
name="a1",
- version="0.8.3",
+ version="0.8.4",
packages=find_packages(exclude=["tests.*", "tests"]),
author="Tommy Carpenter",
description="RIC A1 Mediator for policy/intent changes",
{
"controls":[
{
- "name":"control_admission_time",
- "description":"time period to allow dual connection",
- "message_receives_rmr_type":"DC_ADMISSION_INTERVAL_CONTROL",
+ "name":"admission_control_policy",
+ "description":"various parameters to control admission of dual connection",
+ "control_state_request_rmr_type":"DC_ADM_GET_POLICY",
+ "control_state_request_reply_rmr_type":"DC_ADM_GET_POLICY_ACK",
+ "message_receives_rmr_type":"DC_ADM_INT_CONTROL",
"message_receives_payload_schema":{
"$schema":"http://json-schema.org/draft-07/schema#",
"type":"object",
"properties":{
- "dc_admission_start_time":{
- "type":"string",
- "pattern":"^[0-9]{2}:[0-9]{2}:[0-9]{2}$"
+ "enforce":{
+ "type":"boolean",
+ "default":true
},
- "dc_admission_end_time":{
- "type":"string",
- "pattern":"^[0-9]{2}:[0-9]{2}:[0-9]{2}$"
+ "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"
}
},
- "required":[
- "dc_admission_start_time",
- "dc_admission_end_time"
- ]
+ "additionalProperties":false
},
- "message_sends_rmr_type":"DC_ADMISSION_INTERVAL_CONTROL_ACK",
+ "message_sends_rmr_type":"DC_ADM_INT_CONTROL_ACK",
"message_sends_payload_schema":{
"$schema":"http://json-schema.org/draft-07/schema#",
"type":"object",
"message":{
"type":"string"
}
- }
+ },
+ "required":[
+ "status"
+ ],
+ "additionalProperties":false
}
},
{
-DC_ADMISSION_INTERVAL_CONTROL:20000
-DC_ADMISSION_INTERVAL_CONTROL_ACK:20001
+DC_ADM_INT_CONTROL:20000
+DC_ADM_INT_CONTROL_ACK:20001
TEST_REQ:10000
TEST_ACK:10001
monkeypatch.setattr("rmr.rmr.generate_and_set_transaction_id", fake_set_transactionid)
+def test_xapp_put_good(client, monkeypatch):
+ """ test policy put good"""
+ _test_put_patch(monkeypatch)
+ monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch))
+ res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
+ assert res.status_code == 200
+ assert res.json == {"status": "SUCCESS", "foo": "bar"}
+
+
def test_xapp_put_bad(client, monkeypatch):
"""Test policy put fails"""
_test_put_patch(monkeypatch)
monkeypatch.setattr(
"a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch, msg_payload={"status": "FAIL", "foo": "bar"})
)
- res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+ res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
assert res.status_code == 502
assert res.json["reason"] == "BAD STATUS"
assert res.json["return_payload"] == {"status": "FAIL", "foo": "bar"}
# return from policy handler has no status field
monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch, msg_payload={"foo": "bar"}))
- res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+ res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
assert res.status_code == 502
assert res.json["reason"] == "NO STATUS"
assert res.json["return_payload"] == {"foo": "bar"}
monkeypatch.setattr(
"a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch, msg_payload="booger", jsonb=False)
)
- res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+ res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
assert res.status_code == 502
assert res.json["reason"] == "NOT JSON"
assert res.json["return_payload"] == "booger"
# bad type
monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch, msg_type=666))
- res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+ res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
assert res.status_code == 504
assert res.data == b"\"A1 was expecting an ACK back but it didn't receive one or didn't recieve the expected ACK\"\n"
# bad state
monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch, msg_state=666))
- res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+ res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
assert res.status_code == 504
assert res.data == b"\"A1 was expecting an ACK back but it didn't receive one or didn't recieve the expected ACK\"\n"
-def test_xapp_put_good(client, monkeypatch):
- """ test policy put good"""
- _test_put_patch(monkeypatch)
-
- # do a good one
- monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch))
- res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
- assert res.status_code == 200
- assert res.json == {"status": "SUCCESS", "foo": "bar"}
-
-
def test_xapp_put_bad_send(client, monkeypatch):
"""
Test bad send failures
"""
testing_helpers.patch_all(monkeypatch)
+ monkeypatch.setattr("a1.a1rmr._dequeue_all_waiting_messages", _fake_dequeue(monkeypatch))
+ res = client.put("/ric/policies/admission_control_policy", json={"not": "expected"})
+ assert res.status_code == 400
+
monkeypatch.setattr("rmr.rmr.rmr_send_msg", rmr_mocks.send_mock_generator(10))
- res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+ res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
assert res.status_code == 504
assert res.data == b'"A1 was unable to send a needed message to a downstream subscriber"\n'
monkeypatch.setattr("rmr.rmr.rmr_send_msg", rmr_mocks.send_mock_generator(5))
- res = client.put("/ric/policies/control_admission_time", json=testing_helpers.good_payload())
+ res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
assert res.status_code == 504
assert res.data == b'"A1 was unable to send a needed message to a downstream subscriber"\n'
assert res.status_code == 404
# bad media type
- res = client.put("/ric/policies/control_admission_time", data="notajson")
+ res = client.put("/ric/policies/admission_control_policy", data="notajson")
assert res.status_code == 415
# test a PUT body against a poliucy not expecting one
monkeypatch.setattr("a1.utils.get_ric_manifest", f)
- res = client.put(
- "/ric/policies/control_admission_time", json=testing_helpers.good_payload(), headers={"Content-Type": "text/plain"}
- )
+ res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
assert res.status_code == 500
assert res.data == b'"A1 was unable to find the required RIC manifest. report this!"\n'
test that we get a 500 with an approrpiate message on a missing rmr rmr_string
"""
testing_helpers.patch_all(monkeypatch, nonexisting_rmr=True)
- res = client.put(
- "/ric/policies/control_admission_time", json=testing_helpers.good_payload(), headers={"Content-Type": "text/plain"}
- )
+ res = client.put("/ric/policies/admission_control_policy", json=testing_helpers.good_payload())
assert res.status_code == 500
assert res.data == b'"A1 does not have a mapping for the desired rmr string. report this!"\n'
def good_payload():
- return {"dc_admission_start_time": "10:00:00", "dc_admission_end_time": "11:00:00"}
+ return {"enforce": True, "window_length": 10, "blocking_rate": 20, "trigger_threshold": 10}
echo "running tavern"
pytest
echo "running ab"
- ab -n 100 -c 10 -u putdata -T application/json http://localhost:10000/ric/policies/control_admission_time
+ ab -n 100 -c 10 -u putdata -T application/json http://localhost:10000/ric/policies/admission_control_policy
commands_post=
helm delete testreceiver
helm del --purge testreceiver
LD_LIBRARY_PATH = /usr/local/lib/
RMR_RCV_RETRY_INTERVAL = 1
RMR_RETRY_TIMES = 2
-commands=pytest --verbose --cov {envsitepackagesdir}/a1 --cov-report html
+commands=
+# Note, before this will work, for the first time on that machine, run ./install_deps.sh
+ pytest --verbose --cov {envsitepackagesdir}/a1 --cov-report html
[testenv:flake8]
basepython = python3.7