Skip to content
Snippets Groups Projects
Commit 500a0a23 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Multiple issue resolutions:

Scripts:
- added missing commands to script run_tests_locally.sh

Device:
- added key formatting inside unsibscribe from monitoring
- added termination attribute in GetState to properly interrupt monitoring loops

Service:
- arranged service component testing, missing fixtures

Monitoring:
- added missing environment variable INFLUX_PORT
parent f71a63fd
No related branches found
No related tags found
1 merge request!54Release 2.0.0
...@@ -18,8 +18,12 @@ K8S_HOSTNAME="kubernetes-master" ...@@ -18,8 +18,12 @@ K8S_HOSTNAME="kubernetes-master"
#kubectl delete namespace $K8S_NAMESPACE #kubectl delete namespace $K8S_NAMESPACE
#kubectl create namespace $K8S_NAMESPACE #kubectl create namespace $K8S_NAMESPACE
#kubectl --namespace $K8S_NAMESPACE apply -f ../manifests/contextservice.yaml #kubectl --namespace $K8S_NAMESPACE apply -f ../manifests/contextservice.yaml
#kubectl --namespace $K8S_NAMESPACE apply -f ../manifests/monitoringservice.yaml
#kubectl create secret generic influxdb-secrets --namespace=$K8S_NAMESPACE --from-literal=INFLUXDB_DB="monitoring" --from-literal=INFLUXDB_ADMIN_USER="teraflow" --from-literal=INFLUXDB_ADMIN_PASSWORD="teraflow" --from-literal=INFLUXDB_HTTP_AUTH_ENABLED="True"
#kubectl create secret generic monitoring-secrets --namespace=$K8S_NAMESPACE --from-literal=INFLUXDB_DATABASE="monitoring" --from-literal=INFLUXDB_USER="teraflow" --from-literal=INFLUXDB_PASSWORD="teraflow" --from-literal=INFLUXDB_HOSTNAME="localhost"
#kubectl --namespace $K8S_NAMESPACE expose deployment contextservice --port=6379 --type=NodePort --name=redis-tests #kubectl --namespace $K8S_NAMESPACE expose deployment contextservice --port=6379 --type=NodePort --name=redis-tests
#echo "Waiting 10 seconds for Redis to start..." #kubectl --namespace $K8S_NAMESPACE expose deployment monitoringservice --port=8086 --type=NodePort --name=influx-tests
#echo "Waiting 10 seconds for Redis/Influx to start..."
#sleep 10 #sleep 10
export REDIS_SERVICE_HOST=$(kubectl get node $K8S_HOSTNAME -o 'jsonpath={.status.addresses[?(@.type=="InternalIP")].address}') export REDIS_SERVICE_HOST=$(kubectl get node $K8S_HOSTNAME -o 'jsonpath={.status.addresses[?(@.type=="InternalIP")].address}')
export REDIS_SERVICE_PORT=$(kubectl get service redis-tests --namespace $K8S_NAMESPACE -o 'jsonpath={.spec.ports[?(@.port==6379)].nodePort}') export REDIS_SERVICE_PORT=$(kubectl get service redis-tests --namespace $K8S_NAMESPACE -o 'jsonpath={.spec.ports[?(@.port==6379)].nodePort}')
......
...@@ -373,7 +373,8 @@ class DeviceServiceServicerImpl(DeviceServiceServicer): ...@@ -373,7 +373,8 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
msg = 'EndPointMonitor({:s}) not found.'.format(str(str_endpoint_monitor_key)) msg = 'EndPointMonitor({:s}) not found.'.format(str(str_endpoint_monitor_key))
raise OperationFailedException('MonitorDeviceKpi', extra_details=msg) raise OperationFailedException('MonitorDeviceKpi', extra_details=msg)
str_endpoint_monitor_kpi_key = key_to_str([device_uuid, db_endpoint_monitor.resource_key], separator=':') endpoint_monitor_resource_key = re.sub('[^A-Za-z0-9]', '.', db_endpoint_monitor.resource_key)
str_endpoint_monitor_kpi_key = key_to_str([device_uuid, endpoint_monitor_resource_key], separator=':')
db_endpoint_monitor_kpi : EndPointMonitorKpiModel = get_object( db_endpoint_monitor_kpi : EndPointMonitorKpiModel = get_object(
self.database, EndPointMonitorKpiModel, str_endpoint_monitor_kpi_key, raise_if_not_found=False) self.database, EndPointMonitorKpiModel, str_endpoint_monitor_kpi_key, raise_if_not_found=False)
if db_endpoint_monitor_kpi is None: if db_endpoint_monitor_kpi is None:
......
...@@ -20,7 +20,7 @@ class MonitoringLoop: ...@@ -20,7 +20,7 @@ class MonitoringLoop:
self._samples_queue = samples_queue self._samples_queue = samples_queue
self._running = threading.Event() self._running = threading.Event()
self._terminate = threading.Event() self._terminate = threading.Event()
self._samples_stream = self._driver.GetState(blocking=True) self._samples_stream = self._driver.GetState(blocking=True, terminate=self._terminate)
self._collector_thread = threading.Thread(target=self._collect, daemon=True) self._collector_thread = threading.Thread(target=self._collect, daemon=True)
def _collect(self) -> None: def _collect(self) -> None:
...@@ -38,7 +38,6 @@ class MonitoringLoop: ...@@ -38,7 +38,6 @@ class MonitoringLoop:
def stop(self): def stop(self):
self._terminate.set() self._terminate.set()
#self._samples_stream.close() # leave the work to the garbage collector by now
self._collector_thread.join() self._collector_thread.join()
class MonitoringLoops: class MonitoringLoops:
......
from typing import Any, Iterator, List, Tuple, Union import threading
from typing import Any, Iterator, List, Optional, Tuple, Union
# Special resource names to request to the driver to retrieve the specified configuration/structural resources. # Special resource names to request to the driver to retrieve the specified configuration/structural resources.
# These resource names should be used with GetConfig() method. # These resource names should be used with GetConfig() method.
...@@ -129,21 +130,30 @@ class _Driver: ...@@ -129,21 +130,30 @@ class _Driver:
""" """
raise NotImplementedError() raise NotImplementedError()
def GetState(self, blocking=False) -> Iterator[Tuple[float, str, Any]]: def GetState(
self, blocking=False, terminate : Optional[threading.Event] = None
) -> Iterator[Tuple[float, str, Any]]:
""" Retrieve last collected values for subscribed resources. Operates as a generator, so this method should be """ Retrieve last collected values for subscribed resources. Operates as a generator, so this method should be
called once and will block until values are available. When values are available, it should yield each of called once and will block until values are available. When values are available, it should yield each of
them and block again until new values are available. When the driver is destroyed, GetState() can return them and block again until new values are available. When the driver is destroyed, GetState() can return
instead of yield to terminate the loop. instead of yield to terminate the loop. Terminate enables to request interruption of the generation.
Examples: Examples:
# keep looping waiting for extra samples (generator loop) # keep looping waiting for extra samples (generator loop)
for timestamp,resource_key,resource_value in my_driver.GetState(blocking=True): terminate = threading.Event()
i = 0
for timestamp,resource_key,resource_value in my_driver.GetState(blocking=True, terminate=terminate):
process(timestamp, resource_key, resource_value) process(timestamp, resource_key, resource_value)
i += 1
if i == 10: terminate.set()
# just retrieve accumulated samples # just retrieve accumulated samples
samples = my_driver.GetState(blocking=False) samples = my_driver.GetState(blocking=False, terminate=terminate)
# or (as classical loop) # or (as classical loop)
for timestamp,resource_key,resource_value in my_driver.GetState(blocking=False): i = 0
for timestamp,resource_key,resource_value in my_driver.GetState(blocking=False, terminate=terminate):
process(timestamp, resource_key, resource_value) process(timestamp, resource_key, resource_value)
i += 1
if i == 10: terminate.set()
Parameters: Parameters:
blocking : bool blocking : bool
Select the driver behaviour. In both cases, the driver will first retrieve the samples accumulated Select the driver behaviour. In both cases, the driver will first retrieve the samples accumulated
...@@ -152,6 +162,8 @@ class _Driver: ...@@ -152,6 +162,8 @@ class _Driver:
terminates the loop and returns. Non-blocking behaviour can be used for periodically polling the terminates the loop and returns. Non-blocking behaviour can be used for periodically polling the
driver, while blocking can be used when a separate thread is in charge of collecting the samples driver, while blocking can be used when a separate thread is in charge of collecting the samples
produced by the driver. produced by the driver.
terminate : threading.Event
Signals the interruption of the GetState method as soon as possible.
Returns: Returns:
results : Iterator[Tuple[float, str, Any]] results : Iterator[Tuple[float, str, Any]]
Sequences of state sample. Each State sample contains a float Unix-like timestamps of the samples in Sequences of state sample. Each State sample contains a float Unix-like timestamps of the samples in
......
...@@ -332,8 +332,10 @@ class EmulatedDriver(_Driver): ...@@ -332,8 +332,10 @@ class EmulatedDriver(_Driver):
results.append(True) results.append(True)
return results return results
def GetState(self, blocking=False) -> Iterator[Tuple[str, Any]]: def GetState(self, blocking=False, terminate : Optional[threading.Event] = None) -> Iterator[Tuple[str, Any]]:
while not self.__terminate.is_set(): while True:
if self.__terminate.is_set(): break
if terminate is not None and terminate.is_set(): break
try: try:
sample = self.__out_samples.get(block=blocking, timeout=0.1) sample = self.__out_samples.get(block=blocking, timeout=0.1)
except queue.Empty: except queue.Empty:
......
...@@ -212,7 +212,7 @@ class P4Driver(_Driver): ...@@ -212,7 +212,7 @@ class P4Driver(_Driver):
LOGGER.info('P4 GetResource()') LOGGER.info('P4 GetResource()')
return "" return ""
def GetState(self, blocking=False) -> Iterator[Tuple[str, Any]]: def GetState(self, blocking=False, terminate : Optional[threading.Event] = None) -> Iterator[Tuple[str, Any]]:
""" """
Retrieves the state of a P4 device. Retrieves the state of a P4 device.
......
import logging, requests, threading import logging, requests, threading
from typing import Any, Iterator, List, Tuple, Union from typing import Any, Iterator, List, Optional, Tuple, Union
from common.type_checkers.Checkers import chk_string, chk_type from common.type_checkers.Checkers import chk_string, chk_type
from device.service.driver_api._Driver import _Driver from device.service.driver_api._Driver import _Driver
from . import ALL_RESOURCE_KEYS from . import ALL_RESOURCE_KEYS
...@@ -92,6 +92,8 @@ class TransportApiDriver(_Driver): ...@@ -92,6 +92,8 @@ class TransportApiDriver(_Driver):
# TODO: TAPI does not support monitoring by now # TODO: TAPI does not support monitoring by now
return [False for _ in subscriptions] return [False for _ in subscriptions]
def GetState(self, blocking=False) -> Iterator[Tuple[float, str, Any]]: def GetState(
self, blocking=False, terminate : Optional[threading.Event] = None
) -> Iterator[Tuple[float, str, Any]]:
# TODO: TAPI does not support monitoring by now # TODO: TAPI does not support monitoring by now
return [] return []
...@@ -39,7 +39,7 @@ unit test monitoring: ...@@ -39,7 +39,7 @@ unit test monitoring:
- docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG" - docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
- docker run --name influxdb -d -p 8086:8086 -e INFLUXDB_DB=$INFLUXDB_DATABASE -e INFLUXDB_ADMIN_USER=$INFLUXDB_USER -e INFLUXDB_ADMIN_PASSWORD=$INFLUXDB_PASSWORD -e INFLUXDB_HTTP_AUTH_ENABLED=True --network=teraflowbridge --rm influxdb:1.8 - docker run --name influxdb -d -p 8086:8086 -e INFLUXDB_DB=$INFLUXDB_DATABASE -e INFLUXDB_ADMIN_USER=$INFLUXDB_USER -e INFLUXDB_ADMIN_PASSWORD=$INFLUXDB_PASSWORD -e INFLUXDB_HTTP_AUTH_ENABLED=True --network=teraflowbridge --rm influxdb:1.8
- sleep 10 - sleep 10
- docker run --name $IMAGE_NAME -d -p 7070:7070 --env INFLUXDB_USER=$INFLUXDB_USER --env INFLUXDB_PASSWORD=$INFLUXDB_PASSWORD --env INFLUXDB_DATABASE=$INFLUXDB_DATABASE --env INFLUXDB_HOSTNAME=influxdb -v "$PWD/src/$IMAGE_NAME/tests:/opt/results" --network=teraflowbridge --rm $CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG - docker run --name $IMAGE_NAME -d -p 7070:7070 --env INFLUXDB_USER=$INFLUXDB_USER --env INFLUXDB_PASSWORD=$INFLUXDB_PASSWORD --env INFLUXDB_DATABASE=$INFLUXDB_DATABASE --env INFLUXDB_HOSTNAME=influxdb --env INFLUXDB_PORT=8086 -v "$PWD/src/$IMAGE_NAME/tests:/opt/results" --network=teraflowbridge --rm $CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG
- sleep 30 - sleep 30
- docker ps -a - docker ps -a
- docker logs $IMAGE_NAME - docker logs $IMAGE_NAME
......
...@@ -92,8 +92,9 @@ class TestServiceHandlers: ...@@ -92,8 +92,9 @@ class TestServiceHandlers:
def test_prepare_environment( def test_prepare_environment(
self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints, self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
contexts, topologies, devices, links, contexts, topologies, devices, links,
context_client : ContextClient, # pylint: disable=redefined-outer-name context_client : ContextClient, # pylint: disable=redefined-outer-name
device_client : DeviceClient): # pylint: disable=redefined-outer-name device_client : DeviceClient, # pylint: disable=redefined-outer-name
service_client : ServiceClient): # pylint: disable=redefined-outer-name
for context in contexts: context_client.SetContext(Context(**context)) for context in contexts: context_client.SetContext(Context(**context))
for topology in topologies: context_client.SetTopology(Topology(**topology)) for topology in topologies: context_client.SetTopology(Topology(**topology))
...@@ -104,6 +105,8 @@ class TestServiceHandlers: ...@@ -104,6 +105,8 @@ class TestServiceHandlers:
def test_service_create_error_cases( def test_service_create_error_cases(
self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints, self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
contexts, topologies, devices, links, contexts, topologies, devices, links,
context_client : ContextClient, # pylint: disable=redefined-outer-name
device_client : DeviceClient, # pylint: disable=redefined-outer-name
service_client : ServiceClient): # pylint: disable=redefined-outer-name service_client : ServiceClient): # pylint: disable=redefined-outer-name
with pytest.raises(grpc.RpcError) as e: with pytest.raises(grpc.RpcError) as e:
...@@ -143,6 +146,8 @@ class TestServiceHandlers: ...@@ -143,6 +146,8 @@ class TestServiceHandlers:
def test_service_create_correct( def test_service_create_correct(
self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints, self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
contexts, topologies, devices, links, contexts, topologies, devices, links,
context_client : ContextClient, # pylint: disable=redefined-outer-name
device_client : DeviceClient, # pylint: disable=redefined-outer-name
service_client : ServiceClient): # pylint: disable=redefined-outer-name service_client : ServiceClient): # pylint: disable=redefined-outer-name
service_client.CreateService(Service(**service_descriptor)) service_client.CreateService(Service(**service_descriptor))
...@@ -151,7 +156,9 @@ class TestServiceHandlers: ...@@ -151,7 +156,9 @@ class TestServiceHandlers:
def test_service_get_created( def test_service_get_created(
self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints, self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
contexts, topologies, devices, links, contexts, topologies, devices, links,
context_client : ContextClient): # pylint: disable=redefined-outer-name context_client : ContextClient, # pylint: disable=redefined-outer-name
device_client : DeviceClient, # pylint: disable=redefined-outer-name
service_client : ServiceClient): # pylint: disable=redefined-outer-name
service_data = context_client.GetService(ServiceId(**service_id)) service_data = context_client.GetService(ServiceId(**service_id))
LOGGER.info('service_data = {:s}'.format(grpc_message_to_json_string(service_data))) LOGGER.info('service_data = {:s}'.format(grpc_message_to_json_string(service_data)))
...@@ -161,6 +168,7 @@ class TestServiceHandlers: ...@@ -161,6 +168,7 @@ class TestServiceHandlers:
self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints, self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
contexts, topologies, devices, links, contexts, topologies, devices, links,
context_client : ContextClient, # pylint: disable=redefined-outer-name context_client : ContextClient, # pylint: disable=redefined-outer-name
device_client : DeviceClient, # pylint: disable=redefined-outer-name
service_client : ServiceClient): # pylint: disable=redefined-outer-name service_client : ServiceClient): # pylint: disable=redefined-outer-name
service_with_settings = copy.deepcopy(service_descriptor) service_with_settings = copy.deepcopy(service_descriptor)
...@@ -181,6 +189,7 @@ class TestServiceHandlers: ...@@ -181,6 +189,7 @@ class TestServiceHandlers:
self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints, self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
contexts, topologies, devices, links, contexts, topologies, devices, links,
context_client : ContextClient, # pylint: disable=redefined-outer-name context_client : ContextClient, # pylint: disable=redefined-outer-name
device_client : DeviceClient, # pylint: disable=redefined-outer-name
service_client : ServiceClient): # pylint: disable=redefined-outer-name service_client : ServiceClient): # pylint: disable=redefined-outer-name
service_with_settings = copy.deepcopy(service_descriptor) service_with_settings = copy.deepcopy(service_descriptor)
...@@ -198,7 +207,9 @@ class TestServiceHandlers: ...@@ -198,7 +207,9 @@ class TestServiceHandlers:
def test_service_get_updated( def test_service_get_updated(
self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints, self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
contexts, topologies, devices, links, contexts, topologies, devices, links,
context_client : ContextClient): # pylint: disable=redefined-outer-name context_client : ContextClient, # pylint: disable=redefined-outer-name
device_client : DeviceClient, # pylint: disable=redefined-outer-name
service_client : ServiceClient): # pylint: disable=redefined-outer-name
service_data = context_client.GetService(ServiceId(**service_id)) service_data = context_client.GetService(ServiceId(**service_id))
LOGGER.info('service_data = {:s}'.format(grpc_message_to_json_string(service_data))) LOGGER.info('service_data = {:s}'.format(grpc_message_to_json_string(service_data)))
...@@ -207,6 +218,8 @@ class TestServiceHandlers: ...@@ -207,6 +218,8 @@ class TestServiceHandlers:
def test_service_delete( def test_service_delete(
self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints, self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
contexts, topologies, devices, links, contexts, topologies, devices, links,
context_client : ContextClient, # pylint: disable=redefined-outer-name
device_client : DeviceClient, # pylint: disable=redefined-outer-name
service_client : ServiceClient): # pylint: disable=redefined-outer-name service_client : ServiceClient): # pylint: disable=redefined-outer-name
service_client.DeleteService(ServiceId(**service_id)) service_client.DeleteService(ServiceId(**service_id))
...@@ -215,8 +228,9 @@ class TestServiceHandlers: ...@@ -215,8 +228,9 @@ class TestServiceHandlers:
def test_cleanup_environment( def test_cleanup_environment(
self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints, self, service_id, service_descriptor, service_endpoint_ids, service_config_rules, service_constraints,
contexts, topologies, devices, links, contexts, topologies, devices, links,
context_client : ContextClient, # pylint: disable=redefined-outer-name context_client : ContextClient, # pylint: disable=redefined-outer-name
device_client : DeviceClient): # pylint: disable=redefined-outer-name device_client : DeviceClient, # pylint: disable=redefined-outer-name
service_client : ServiceClient): # pylint: disable=redefined-outer-name
for link in links: context_client.RemoveLink(LinkId(**link['link_id'])) for link in links: context_client.RemoveLink(LinkId(**link['link_id']))
for device in devices: device_client.DeleteDevice(DeviceId(**device['device_id'])) for device in devices: device_client.DeleteDevice(DeviceId(**device['device_id']))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment