Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • tfs/controller
1 result
Show changes
Commits on Source (6)
Showing
with 930 additions and 354 deletions
#!/bin/bash
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
########################################################################################################################
# Read deployment settings
########################################################################################################################
# If not already set, set the URL of your local Docker registry where the images will be uploaded to.
# Leave it blank if you do not want to use any Docker registry.
export TFS_REGISTRY_IMAGE=${TFS_REGISTRY_IMAGE:-""}
#export TFS_REGISTRY_IMAGE="http://my-container-registry.local/"
TFS_COMPONENTS=$1
# If not already set, set the tag you want to use for your images.
export TFS_IMAGE_TAG=${TFS_IMAGE_TAG:-"dev"}
# If not already set, set the name of the Kubernetes namespace to deploy to.
export TFS_K8S_NAMESPACE=${TFS_K8S_NAMESPACE:-"tfs"}
# If not already set, set additional manifest files to be applied after the deployment
export TFS_EXTRA_MANIFESTS=${TFS_EXTRA_MANIFESTS:-""}
# If not already set, set the neew Grafana admin password
export TFS_GRAFANA_PASSWORD=${TFS_GRAFANA_PASSWORD:-"admin123+"}
########################################################################################################################
# Automated steps start here
########################################################################################################################
# Constants
GITLAB_REPO_URL="registry.gitlab.com/teraflow-h2020/controller"
TMP_FOLDER="./tmp"
# Create a tmp folder for files modified during the deployment
TMP_MANIFESTS_FOLDER="$TMP_FOLDER/manifests"
TMP_LOGS_FOLDER="$TMP_FOLDER/logs"
echo "Deploying component and collecting environment variables..."
ENV_VARS_SCRIPT=tfs_runtime_env_vars.sh
for COMPONENT in $TFS_COMPONENTS; do
echo "Processing '$COMPONENT' component..."
IMAGE_NAME="$COMPONENT:$TFS_IMAGE_TAG"
IMAGE_URL=$(echo "$TFS_REGISTRY_IMAGE/$IMAGE_NAME" | sed 's,//,/,g' | sed 's,http:/,,g')
echo " Building Docker image..."
BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}.log"
if [ "$COMPONENT" == "automation" ] || [ "$COMPONENT" == "policy" ]; then
docker build -t "$IMAGE_NAME" -f ./src/"$COMPONENT"/Dockerfile ./src/"$COMPONENT"/ > "$BUILD_LOG"
elif [ "$COMPONENT" == "pathcomp" ]; then
BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}-frontend.log"
docker build -t "$COMPONENT-frontend:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/frontend/Dockerfile . >> "$BUILD_LOG"
BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}-backend.log"
docker build -t "$COMPONENT-backend:$TFS_IMAGE_TAG" -f ./src/"$COMPONENT"/backend/Dockerfile . >> "$BUILD_LOG"
# next command is redundant, but helpful to keep cache updated between rebuilds
docker build -t "$COMPONENT-backend:$TFS_IMAGE_TAG-builder" --target builder -f ./src/"$COMPONENT"/backend/Dockerfile . >> "$BUILD_LOG"
else
docker build -t "$IMAGE_NAME" -f ./src/"$COMPONENT"/Dockerfile . > "$BUILD_LOG"
fi
if [ -n "$TFS_REGISTRY_IMAGE" ]; then
echo " Pushing Docker image to '$TFS_REGISTRY_IMAGE'..."
if [ "$COMPONENT" == "pathcomp" ]; then
TAG_LOG="$TMP_LOGS_FOLDER/tag_${COMPONENT}-frontend.log"
docker tag "$COMPONENT-frontend:$TFS_IMAGE_TAG" "$IMAGE_URL-frontend" > "$TAG_LOG"
TAG_LOG="$TMP_LOGS_FOLDER/tag_${COMPONENT}-backend.log"
docker tag "$COMPONENT-backend:$TFS_IMAGE_TAG" "$IMAGE_URL-backend" > "$TAG_LOG"
PUSH_LOG="$TMP_LOGS_FOLDER/push_${COMPONENT}-frontend.log"
docker push "$IMAGE_URL-frontend" > "$PUSH_LOG"
PUSH_LOG="$TMP_LOGS_FOLDER/push_${COMPONENT}-backend.log"
docker push "$IMAGE_URL-backend" > "$PUSH_LOG"
else
TAG_LOG="$TMP_LOGS_FOLDER/tag_${COMPONENT}.log"
docker tag "$IMAGE_NAME" "$IMAGE_URL" > "$TAG_LOG"
PUSH_LOG="$TMP_LOGS_FOLDER/push_${COMPONENT}.log"
docker push "$IMAGE_URL" > "$PUSH_LOG"
fi
fi
echo " Adapting '$COMPONENT' manifest file..."
MANIFEST="$TMP_MANIFESTS_FOLDER/${COMPONENT}service.yaml"
cp ./manifests/"${COMPONENT}"service.yaml "$MANIFEST"
if [ -n "$TFS_REGISTRY_IMAGE" ]; then
# Registry is set
if [ "$COMPONENT" == "pathcomp" ]; then
VERSION=$(grep -i "${GITLAB_REPO_URL}/${COMPONENT}-frontend:" "$MANIFEST" | cut -d ":" -f3)
sed -E -i "s#image: $GITLAB_REPO_URL/$COMPONENT-frontend:${VERSION}#image: $IMAGE_URL-frontend#g" "$MANIFEST"
VERSION=$(grep -i "${GITLAB_REPO_URL}/${COMPONENT}-backend:" "$MANIFEST" | cut -d ":" -f3)
sed -E -i "s#image: $GITLAB_REPO_URL/$COMPONENT-backend:${VERSION}#image: $IMAGE_URL-backend#g" "$MANIFEST"
sed -E -i "s#imagePullPolicy: .*#imagePullPolicy: Always#g" "$MANIFEST"
else
VERSION=$(grep -i "${GITLAB_REPO_URL}/${COMPONENT}:" "$MANIFEST" | cut -d ":" -f3)
sed -E -i "s#image: $GITLAB_REPO_URL/$COMPONENT:${VERSION}#image: $IMAGE_URL#g" "$MANIFEST"
sed -E -i "s#imagePullPolicy: .*#imagePullPolicy: Always#g" "$MANIFEST"
fi
else
# Registry is not set
if [ "$COMPONENT" == "pathcomp" ]; then
VERSION=$(grep -i "${GITLAB_REPO_URL}/${COMPONENT}-frontend:" "$MANIFEST" | cut -d ":" -f3)
sed -E -i "s#image: $GITLAB_REPO_URL/$COMPONENT-frontend:${VERSION}#image: $IMAGE_NAME-frontend#g" "$MANIFEST"
VERSION=$(grep -i "${GITLAB_REPO_URL}/${COMPONENT}-backend:" "$MANIFEST" | cut -d ":" -f3)
sed -E -i "s#image: $GITLAB_REPO_URL/$COMPONENT-backend:${VERSION}#image: $IMAGE_NAME-backend#g" "$MANIFEST"
sed -E -i "s#imagePullPolicy: .*#imagePullPolicy: Never#g" "$MANIFEST"
else
VERSION=$(grep -i "${GITLAB_REPO_URL}/${COMPONENT}:" "$MANIFEST" | cut -d ":" -f3)
sed -E -i "s#image: $GITLAB_REPO_URL/$COMPONENT:${VERSION}#image: $IMAGE_NAME#g" "$MANIFEST"
sed -E -i "s#imagePullPolicy: .*#imagePullPolicy: Never#g" "$MANIFEST"
fi
fi
# TODO: harmonize names of the monitoring component
echo " Deploying '$COMPONENT' component to Kubernetes..."
DEPLOY_LOG="$TMP_LOGS_FOLDER/deploy_${COMPONENT}.log"
kubectl --namespace $TFS_K8S_NAMESPACE delete -f "$MANIFEST" > "$DEPLOY_LOG"
kubectl --namespace $TFS_K8S_NAMESPACE apply -f "$MANIFEST" > "$DEPLOY_LOG"
COMPONENT_OBJNAME=$(echo "${COMPONENT}" | sed "s/\_/-/")
kubectl --namespace $TFS_K8S_NAMESPACE scale deployment --replicas=0 ${COMPONENT_OBJNAME}service >> "$DEPLOY_LOG"
kubectl --namespace $TFS_K8S_NAMESPACE scale deployment --replicas=1 ${COMPONENT_OBJNAME}service >> "$DEPLOY_LOG"
echo " Collecting env-vars for '$COMPONENT' component..."
SERVICE_DATA=$(kubectl get service ${COMPONENT}service --namespace $TFS_K8S_NAMESPACE -o json)
if [ -z "${SERVICE_DATA}" ]; then continue; fi
# Env vars for service's host address
SERVICE_HOST=$(echo ${SERVICE_DATA} | jq -r '.spec.clusterIP')
if [ -z "${SERVICE_HOST}" ]; then continue; fi
# TODO: remove previous value from file
ENVVAR_HOST=$(echo "${COMPONENT}service_SERVICE_HOST" | tr '[:lower:]' '[:upper:]')
echo "export ${ENVVAR_HOST}=${SERVICE_HOST}" >> $ENV_VARS_SCRIPT
# Env vars for service's 'grpc' port (if any)
SERVICE_PORT_GRPC=$(echo ${SERVICE_DATA} | jq -r '.spec.ports[] | select(.name=="grpc") | .port')
if [ -n "${SERVICE_PORT_GRPC}" ]; then
ENVVAR_PORT_GRPC=$(echo "${COMPONENT}service_SERVICE_PORT_GRPC" | tr '[:lower:]' '[:upper:]')
echo "export ${ENVVAR_PORT_GRPC}=${SERVICE_PORT_GRPC}" >> $ENV_VARS_SCRIPT
fi
# Env vars for service's 'http' port (if any)
SERVICE_PORT_HTTP=$(echo ${SERVICE_DATA} | jq -r '.spec.ports[] | select(.name=="http") | .port')
if [ -n "${SERVICE_PORT_HTTP}" ]; then
ENVVAR_PORT_HTTP=$(echo "${COMPONENT}service_SERVICE_PORT_HTTP" | tr '[:lower:]' '[:upper:]')
echo "export ${ENVVAR_PORT_HTTP}=${SERVICE_PORT_HTTP}" >> $ENV_VARS_SCRIPT
fi
printf "\n"
done
# By now, leave this control here. Some component dependencies are not well handled
for COMPONENT in $TFS_COMPONENTS; do
echo "Waiting for '$COMPONENT' component..."
kubectl wait --namespace $TFS_K8S_NAMESPACE \
--for='condition=available' --timeout=300s deployment/${COMPONENT}service
printf "\n"
done
./show_deploy.sh
echo "Done!"
......@@ -239,6 +239,7 @@ enum ServiceTypeEnum {
SERVICETYPE_L3NM = 1;
SERVICETYPE_L2NM = 2;
SERVICETYPE_TAPI_CONNECTIVITY_SERVICE = 3;
SERVICETYPE_P4 = 4;
}
enum ServiceStatusEnum {
......
......@@ -15,7 +15,7 @@
import json, logging
from typing import Dict, List, Tuple
from common.proto.context_pb2 import (
ConnectionEvent, ContextEvent, DeviceEvent, EventTypeEnum, LinkEvent, ServiceEvent, TopologyEvent)
ConnectionEvent, ContextEvent, DeviceEvent, EventTypeEnum, LinkEvent, ServiceEvent, SliceEvent, TopologyEvent)
from common.tools.grpc.Tools import grpc_message_to_json_string
from context.client.EventsCollector import EventsCollector
......@@ -32,6 +32,7 @@ CLASSNAME_CONTEXT_EVENT = class_to_classname(ContextEvent)
CLASSNAME_TOPOLOGY_EVENT = class_to_classname(TopologyEvent)
CLASSNAME_DEVICE_EVENT = class_to_classname(DeviceEvent)
CLASSNAME_LINK_EVENT = class_to_classname(LinkEvent)
CLASSNAME_SLICE_EVENT = class_to_classname(SliceEvent)
CLASSNAME_SERVICE_EVENT = class_to_classname(ServiceEvent)
CLASSNAME_CONNECTION_EVENT = class_to_classname(ConnectionEvent)
......@@ -40,6 +41,7 @@ EVENT_CLASS_NAME__TO__ENTITY_ID_SELECTOR = {
CLASSNAME_TOPOLOGY_EVENT : lambda event: event.topology_id,
CLASSNAME_DEVICE_EVENT : lambda event: event.device_id,
CLASSNAME_LINK_EVENT : lambda event: event.link_id,
CLASSNAME_SLICE_EVENT : lambda event: event.slice_id,
CLASSNAME_SERVICE_EVENT : lambda event: event.service_id,
CLASSNAME_CONNECTION_EVENT: lambda event: event.connection_id,
}
......
......@@ -98,10 +98,8 @@ def process_site_network_access(context_client : ContextClient, site_id : str, s
if circuit_id is not None: field_updates['circuit_id' ] = (circuit_id, True)
update_config_rule_custom(config_rules, endpoint_settings_key, field_updates)
field_updates = {}
if len(diversity_constraints) > 0:
field_updates.update(diversity_constraints)
update_constraint_custom(constraints, 'diversity', field_updates)
update_constraint_custom(constraints, 'diversity', diversity_constraints)
update_constraint_endpoint_location(constraints, endpoint_id, region=site_id)
if access_priority is not None: update_constraint_endpoint_priority(constraints, endpoint_id, access_priority)
......
......@@ -371,7 +371,7 @@ class WimconnectorIETFL2VPN(SdnConnectorBase):
self.delete_connectivity_service(vpn_service["vpn-id"])
raise SdnConnectorError(
"Request no accepted",
"Request not accepted",
http_code=response_endpoint_site_network_access_creation.status_code,
)
except requests.exceptions.ConnectionError:
......
......@@ -34,7 +34,6 @@ class EndPointModel(Model):
device_fk = ForeignKeyField(DeviceModel)
endpoint_uuid = StringField(required=True, allow_empty=False)
endpoint_type = StringField()
resource_key = StringField(required=True, allow_empty=False)
def dump_id(self) -> Dict:
device_id = DeviceModel(self.database, self.device_fk).dump_id()
......@@ -74,13 +73,7 @@ def set_endpoint_monitors(database : Database, db_endpoint : EndPointModel, grpc
for kpi_sample_type in grpc_endpoint_kpi_sample_types:
orm_kpi_sample_type = grpc_to_enum__kpi_sample_type(kpi_sample_type)
str_endpoint_kpi_sample_type_key = key_to_str([db_endpoint_pk, str(orm_kpi_sample_type.value)])
#db_endpoint_kpi_sample_type = EndPointMonitorModel(database, str_endpoint_kpi_sample_type_key)
#db_endpoint_kpi_sample_type.endpoint_fk = db_endpoint
#db_endpoint_kpi_sample_type.resource_key = '' # during initialization, allow empty value
#db_endpoint_kpi_sample_type.kpi_sample_type = orm_kpi_sample_type
#db_endpoint_kpi_sample_type.save()
update_or_create_object(database, EndPointMonitorModel, str_endpoint_kpi_sample_type_key, {
'endpoint_fk' : db_endpoint,
#'resource_key' : '', # during initialization, allow empty value
'kpi_sample_type': orm_kpi_sample_type,
})
......@@ -34,6 +34,7 @@ class ORM_ServiceTypeEnum(Enum):
L3NM = ServiceTypeEnum.SERVICETYPE_L3NM
L2NM = ServiceTypeEnum.SERVICETYPE_L2NM
TAPI_CONNECTIVITY_SERVICE = ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE
P4_SERVICE = ServiceTypeEnum.SERVICETYPE_P4
grpc_to_enum__service_type = functools.partial(
grpc_to_enum, ServiceTypeEnum, ORM_ServiceTypeEnum)
......
......@@ -17,6 +17,7 @@ from ..service_handler_api.FilterFields import FilterFieldEnum
from .l2nm_emulated.L2NMEmulatedServiceHandler import L2NMEmulatedServiceHandler
from .l3nm_emulated.L3NMEmulatedServiceHandler import L3NMEmulatedServiceHandler
from .l3nm_openconfig.L3NMOpenConfigServiceHandler import L3NMOpenConfigServiceHandler
from .p4.p4_service_handler import P4ServiceHandler
from .tapi_tapi.TapiServiceHandler import TapiServiceHandler
SERVICE_HANDLERS = [
......@@ -44,4 +45,10 @@ SERVICE_HANDLERS = [
FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API,
}
]),
(P4ServiceHandler, [
{
FilterFieldEnum.SERVICE_TYPE: ORM_ServiceTypeEnum.P4_SERVICE,
FilterFieldEnum.DEVICE_DRIVER: ORM_DeviceDriverEnum.P4,
}
]),
]
......@@ -20,7 +20,7 @@ def setup_config_rules(
service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str,
service_settings : TreeNode, endpoint_settings : TreeNode
) -> List[Dict]:
json_settings : Dict = {} if service_settings is None else service_settings.value
json_endpoint_settings : Dict = {} if endpoint_settings is None else endpoint_settings.value
......
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Dict, List
from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set
from service.service.service_handler_api.AnyTreeTools import TreeNode
def setup_config_rules(
service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str,
service_settings : TreeNode, endpoint_settings : TreeNode
) -> List[Dict]:
json_settings : Dict = {} if service_settings is None else service_settings.value
json_endpoint_settings : Dict = {} if endpoint_settings is None else endpoint_settings.value
service_short_uuid = service_uuid.split('-')[-1]
network_instance_name = '{:s}-NetInst'.format(service_short_uuid)
network_interface_desc = '{:s}-NetIf'.format(service_uuid)
network_subinterface_desc = '{:s}-NetSubIf'.format(service_uuid)
mtu = json_settings.get('mtu', 1450 ) # 1512
#address_families = json_settings.get('address_families', [] ) # ['IPV4']
bgp_as = json_settings.get('bgp_as', 0 ) # 65000
bgp_route_target = json_settings.get('bgp_route_target', '0:0') # 65000:333
#router_id = json_endpoint_settings.get('router_id', '0.0.0.0') # '10.95.0.10'
route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0' ) # '60001:801'
sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0 ) # 1
vlan_id = json_endpoint_settings.get('vlan_id', 1 ) # 400
address_ip = json_endpoint_settings.get('address_ip', '0.0.0.0') # '2.2.2.1'
address_prefix = json_endpoint_settings.get('address_prefix', 24 ) # 30
if_subif_name = '{:s}.{:d}'.format(endpoint_uuid, vlan_id)
json_config_rules = [
json_config_rule_set(
'/network_instance[{:s}]'.format(network_instance_name), {
'name': network_instance_name, 'description': network_interface_desc, 'type': 'L3VRF',
'route_distinguisher': route_distinguisher,
#'router_id': router_id, 'address_families': address_families,
}),
json_config_rule_set(
'/interface[{:s}]'.format(endpoint_uuid), {
'name': endpoint_uuid, 'description': network_interface_desc, 'mtu': mtu,
}),
json_config_rule_set(
'/interface[{:s}]/subinterface[{:d}]'.format(endpoint_uuid, sub_interface_index), {
'name': endpoint_uuid, 'index': sub_interface_index,
'description': network_subinterface_desc, 'vlan_id': vlan_id,
'address_ip': address_ip, 'address_prefix': address_prefix,
}),
json_config_rule_set(
'/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), {
'name': network_instance_name, 'id': if_subif_name, 'interface': endpoint_uuid,
'subinterface': sub_interface_index,
}),
json_config_rule_set(
'/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), {
'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP', 'as': bgp_as,
}),
json_config_rule_set(
'/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), {
'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP',
'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
}),
json_config_rule_set(
'/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format(
network_instance_name), {
'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP',
'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
}),
json_config_rule_set(
'/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), {
'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
}),
json_config_rule_set(
'/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format(
network_instance_name, bgp_route_target), {
'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
}),
json_config_rule_set(
'/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), {
'policy_name': '{:s}_import'.format(network_instance_name),
}),
json_config_rule_set(
'/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format(
network_instance_name, '3'), {
'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3',
'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
}),
json_config_rule_set(
# pylint: disable=duplicate-string-formatting-argument
'/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format(
network_instance_name, network_instance_name), {
'name': network_instance_name, 'import_policy': '{:s}_import'.format(network_instance_name),
}),
json_config_rule_set(
'/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), {
'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
}),
json_config_rule_set(
'/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format(
network_instance_name, bgp_route_target), {
'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
}),
json_config_rule_set(
'/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), {
'policy_name': '{:s}_export'.format(network_instance_name),
}),
json_config_rule_set(
'/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format(
network_instance_name, '3'), {
'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3',
'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
}),
json_config_rule_set(
# pylint: disable=duplicate-string-formatting-argument
'/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format(
network_instance_name, network_instance_name), {
'name': network_instance_name, 'export_policy': '{:s}_export'.format(network_instance_name),
}),
]
return json_config_rules
def teardown_config_rules(
service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str,
service_settings : TreeNode, endpoint_settings : TreeNode
) -> List[Dict]:
json_settings : Dict = {} if service_settings is None else service_settings.value
json_endpoint_settings : Dict = {} if endpoint_settings is None else endpoint_settings.value
#mtu = json_settings.get('mtu', 1450 ) # 1512
#address_families = json_settings.get('address_families', [] ) # ['IPV4']
#bgp_as = json_settings.get('bgp_as', 0 ) # 65000
bgp_route_target = json_settings.get('bgp_route_target', '0:0') # 65000:333
#router_id = json_endpoint_settings.get('router_id', '0.0.0.0') # '10.95.0.10'
#route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0' ) # '60001:801'
sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0 ) # 1
vlan_id = json_endpoint_settings.get('vlan_id', 1 ) # 400
#address_ip = json_endpoint_settings.get('address_ip', '0.0.0.0') # '2.2.2.1'
#address_prefix = json_endpoint_settings.get('address_prefix', 24 ) # 30
if_subif_name = '{:s}.{:d}'.format(endpoint_uuid, vlan_id)
service_short_uuid = service_uuid.split('-')[-1]
network_instance_name = '{:s}-NetInst'.format(service_short_uuid)
#network_interface_desc = '{:s}-NetIf'.format(service_uuid)
#network_subinterface_desc = '{:s}-NetSubIf'.format(service_uuid)
json_config_rules = [
json_config_rule_delete(
'/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), {
'name': network_instance_name, 'id': if_subif_name,
}),
json_config_rule_delete(
'/interface[{:s}]/subinterface[{:d}]'.format(endpoint_uuid, sub_interface_index), {
'name': endpoint_uuid, 'index': sub_interface_index,
}),
json_config_rule_delete(
'/interface[{:s}]'.format(endpoint_uuid), {
'name': endpoint_uuid,
}),
json_config_rule_delete(
'/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format(
network_instance_name), {
'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP',
'address_family': 'IPV4',
}),
json_config_rule_delete(
'/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), {
'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP',
'address_family': 'IPV4',
}),
json_config_rule_delete(
'/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), {
'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP',
}),
json_config_rule_delete(
# pylint: disable=duplicate-string-formatting-argument
'/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format(
network_instance_name, network_instance_name), {
'name': network_instance_name,
}),
json_config_rule_delete(
'/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format(
network_instance_name, '3'), {
'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3',
}),
json_config_rule_delete(
'/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), {
'policy_name': '{:s}_import'.format(network_instance_name),
}),
json_config_rule_delete(
'/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format(
network_instance_name, bgp_route_target), {
'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
}),
json_config_rule_delete(
'/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), {
'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
}),
json_config_rule_delete(
# pylint: disable=duplicate-string-formatting-argument
'/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format(
network_instance_name, network_instance_name), {
'name': network_instance_name,
}),
json_config_rule_delete(
'/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format(
network_instance_name, '3'), {
'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3',
}),
json_config_rule_delete(
'/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), {
'policy_name': '{:s}_export'.format(network_instance_name),
}),
json_config_rule_delete(
'/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format(
network_instance_name, bgp_route_target), {
'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
}),
json_config_rule_delete(
'/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), {
'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
}),
json_config_rule_delete(
'/network_instance[{:s}]'.format(network_instance_name), {
'name': network_instance_name
}),
]
return json_config_rules
# json_endpoint_settings : Dict = endpoint_settings.value
# #router_id = json_endpoint_settings.get('router_id', '0.0.0.0') # '10.95.0.10'
# route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0' ) # '60001:801'
# sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0 ) # 1
# vlan_id = json_endpoint_settings.get('vlan_id', 1 ) # 400
# address_ip = json_endpoint_settings.get('address_ip', '0.0.0.0') # '2.2.2.1'
# address_prefix = json_endpoint_settings.get('address_prefix', 24 ) # 30
# if_subif_name = '{:s}.{:d}'.format(endpoint_uuid, vlan_id)
# db_device : DeviceModel = get_object(self.__database, DeviceModel, device_uuid, raise_if_not_found=True)
# device = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
# json_device = db_device.dump(include_config_rules=False, include_drivers=True, include_endpoints=True)
# json_device_config : Dict = json_device.setdefault('device_config', {})
# json_device_config_rules : List = json_device_config.setdefault('config_rules', [])
# json_device_config_rules.extend([
# json_config_rule_set(
# '/network_instance[{:s}]'.format(network_instance_name), {
# 'name': network_instance_name, 'description': network_interface_desc, 'type': 'L3VRF',
# 'route_distinguisher': route_distinguisher,
# #'router_id': router_id, 'address_families': address_families,
# }),
# json_config_rule_set(
# '/interface[{:s}]'.format(endpoint_uuid), {
# 'name': endpoint_uuid, 'description': network_interface_desc, 'mtu': mtu,
# }),
# json_config_rule_set(
# '/interface[{:s}]/subinterface[{:d}]'.format(endpoint_uuid, sub_interface_index), {
# 'name': endpoint_uuid, 'index': sub_interface_index,
# 'description': network_subinterface_desc, 'vlan_id': vlan_id,
# 'address_ip': address_ip, 'address_prefix': address_prefix,
# }),
# json_config_rule_set(
# '/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), {
# 'name': network_instance_name, 'id': if_subif_name, 'interface': endpoint_uuid,
# 'subinterface': sub_interface_index,
# }),
# json_config_rule_set(
# '/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), {
# 'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP', 'as': bgp_as,
# }),
# json_config_rule_set(
# '/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), {
# 'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP',
# 'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
# }),
# json_config_rule_set(
# '/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format(
# network_instance_name), {
# 'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP',
# 'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
# }),
# json_config_rule_set(
# '/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), {
# 'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
# }),
# json_config_rule_set(
# '/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format(
# network_instance_name, bgp_route_target), {
# 'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
# 'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
# }),
# json_config_rule_set(
# '/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), {
# 'policy_name': '{:s}_import'.format(network_instance_name),
# }),
# json_config_rule_set(
# '/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format(
# network_instance_name, '3'), {
# 'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3',
# 'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
# 'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
# }),
# json_config_rule_set(
# # pylint: disable=duplicate-string-formatting-argument
# '/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format(
# network_instance_name, network_instance_name), {
# 'name': network_instance_name, 'import_policy': '{:s}_import'.format(network_instance_name),
# }),
# json_config_rule_set(
# '/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), {
# 'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
# }),
# json_config_rule_set(
# '/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format(
# network_instance_name, bgp_route_target), {
# 'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
# 'ext_community_member' : 'route-target:{:s}'.format(bgp_route_target),
# }),
# json_config_rule_set(
# '/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), {
# 'policy_name': '{:s}_export'.format(network_instance_name),
# }),
# json_config_rule_set(
# '/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format(
# network_instance_name, '3'), {
# 'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3',
# 'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
# 'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
# }),
# json_config_rule_set(
# # pylint: disable=duplicate-string-formatting-argument
# '/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format(
# network_instance_name, network_instance_name), {
# 'name': network_instance_name, 'export_policy': '{:s}_export'.format(network_instance_name),
# }),
# ])
# self.__device_client.ConfigureDevice(Device(**json_device))
# results.append(True)
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
P4 service handler for the TeraFlow SDN controller.
"""
import json
import logging
from typing import Any, List, Optional, Tuple, Union
from common.orm.Database import Database
from common.orm.HighLevel import get_object
from common.orm.backend.Tools import key_to_str
# from common.proto.context_pb2 import Device
# from common.tools.object_factory.ConfigRule import json_config_rule_delete,\
# json_config_rule_set
from common.type_checkers.Checkers import chk_type
from context.client.ContextClient import ContextClient
from device.client.DeviceClient import DeviceClient
from service.service.database.ConfigModel import get_config_rules
from service.service.database.ContextModel import ContextModel
# from service.service.database.DeviceModel import DeviceModel
from service.service.database.ServiceModel import ServiceModel
from service.service.service_handler_api._ServiceHandler import _ServiceHandler
LOGGER = logging.getLogger(__name__)
class P4ServiceHandler(_ServiceHandler):
"""
P4ServiceHandler class inherits the abstract _ServiceHandler class
to provision network connectivity upon P4 devices.
Attributes
----------
db_service: ServiceModel
The service instance from the local in-memory database.
database: Database
The instance of the local in-memory database.
context_client: ContextClient
gRPC client to get Context services
device_client : DeviceClient
gRPC client to get Device services
settings: map
Extra settings required by the service handler.
"""
def __init__(self, # pylint: disable=super-init-not-called
db_service: ServiceModel,
database: Database,
context_client: ContextClient,
device_client : DeviceClient,
**settings) -> None:
self.__db_service = db_service
self.__database = database
self.__context_client = context_client
self.__device_client = device_client
self.__db_context: ContextModel = get_object(
self.__database, ContextModel, self.__db_service.context_fk)
str_service_key = key_to_str(
[self.__db_context.context_uuid, self.__db_service.service_uuid])
db_config = get_config_rules(
self.__database, str_service_key, "running")
self.__resolver = None
self.__config = None
def SetEndpoint(self, endpoints: List[Tuple[str, str, Optional[str]]]) \
-> List[Union[bool, Exception]]:
"""
Create/Update service endpoints.
:param endpoints: list of tuples, each containing a device_uuid,
endpoint_uuid and, optionally, the topology_uuid of the endpoint to add.
:return: list of results for endpoint changes requested.
Return values must be in the same order as the requested endpoints.
If an endpoint is properly added, True must be returned;
otherwise, the Exception that is raised during processing
must be returned.
"""
chk_type("endpoints", endpoints, list)
if len(endpoints) == 0:
return []
return []
def DeleteEndpoint(self, endpoints: List[Tuple[str, str, Optional[str]]]) \
-> List[Union[bool, Exception]]:
"""
Delete service endpoints.
:param endpoints: list of tuples, each containing a device_uuid,
endpoint_uuid and, optionally, the topology_uuid of the endpoint to
delete.
:return: list of results for endpoint deletions requested.
Return values must be in the same order as the requested endpoints.
If an endpoint is properly deleted, True must be returned;
otherwise, the Exception that is raised during processing
must be returned.
"""
chk_type("endpoints", endpoints, list)
if len(endpoints) == 0:
return []
return []
def SetConstraint(self, constraints: List[Tuple[str, Any]]) \
-> List[Union[bool, Exception]]:
"""
Create/Update service constraints.
:param constraints: List of tuples, each containing a constraint_type
and the new constraint_value to be set.
:return: List of results for constraint changes requested.
Return values must be in the same order as the requested constraints.
If a constraint is properly set, True must be returned;
otherwise, the Exception that is raised during the processing
must be returned.
"""
chk_type("constraints", constraints, list)
if len(constraints) == 0:
return []
msg = f"SetConstraint() not yet implemented by the" \
f" P4 service handler. \nThe following constraints " \
f"are being ignored: {str(constraints)}"
LOGGER.warning(msg)
return [Exception(msg) for _ in range(len(constraints))]
def DeleteConstraint(self, constraints: List[Tuple[str, Any]]) \
-> List[Union[bool, Exception]]:
"""
Delete service constraints.
:param constraints: List of tuples, each containing a constraint_type
pointing to the constraint to be deleted, and a constraint_value
containing possible additionally required values to locate the
constraint to be removed.
:return: List of results for constraint deletions requested.
Return values must be in the same order as the requested constraints.
If a constraint is properly deleted, True must be returned;
otherwise, the Exception that is raised during the processing
must be returned.
"""
chk_type("constraints", constraints, list)
if len(constraints) == 0:
return []
msg = f"DeleteConstraint() not yet implemented by the" \
f" P4 service handler. \nThe following constraints " \
f"are being ignored: {str(constraints)}"
LOGGER.warning(msg)
return [Exception(msg) for _ in range(len(constraints))]
def SetConfig(self, resources: List[Tuple[str, Any]]) \
-> List[Union[bool, Exception]]:
"""
Create/Update configuration for a list of service resources.
:param resources: List of tuples, each containing a resource_key
pointing to the resource to be modified, and a resource_value
containing the new value to be set.
:return: List of results for resource key changes requested.
Return values must be in the same order as the requested resource keys.
If a resource is properly set, True must be returned;
otherwise, the Exception that is raised during the processing
must be returned.
"""
chk_type("resources", resources, list)
if len(resources) == 0:
return []
results = []
for resource in resources:
try:
resource_key, resource_value = resource
resource_value = json.loads(resource_value)
# Do the job
# results.append(True)
except Exception as ex: # pylint: disable=broad-except
LOGGER.exception(
"Failed to execute SetConfig(%s)", str(resource))
results.append(ex)
return results
def DeleteConfig(self, resources: List[Tuple[str, Any]]) \
-> List[Union[bool, Exception]]:
"""
Delete configuration for a list of service resources.
:param resources: List of tuples, each containing a resource_key
pointing to the resource to be modified, and a resource_value containing
possible additionally required values to locate the value to be removed.
:return: List of results for resource key deletions requested.
Return values must be in the same order as the requested resource keys.
If a resource is properly deleted, True must be returned;
otherwise, the Exception that is raised during the processing
must be returned.
"""
chk_type("resources", resources, list)
if len(resources) == 0:
return []
results = []
for resource in resources:
try:
resource_key, _ = resource
# Do the job
# results.append(True)
except Exception as ex: # pylint: disable=broad-except
LOGGER.exception(
"Failed to execute DeleteConfig(%s)", str(resource))
results.append(ex)
return results
......@@ -15,12 +15,11 @@
import copy, grpc, logging, pytest
from common.proto.context_pb2 import (
Context, ContextId, Device, DeviceId, Link, LinkId, Service, ServiceId, Topology, TopologyId)
from common.tests.PytestGenerateTests import pytest_generate_tests # (required) pylint: disable=unused-import
from common.tools.grpc.Tools import grpc_message_to_json_string
from context.client.ContextClient import ContextClient
from device.client.DeviceClient import DeviceClient
from service.client.ServiceClient import ServiceClient
from .PrepareTestScenario import ( # pylint: disable=unused-import
from .PrepareTestScenario import ( # pylint: disable=unused-import
# be careful, order of symbols is important here!
mock_service, service_service, context_client, device_client, service_client)
......
......@@ -59,10 +59,10 @@ def test_scenario_empty(context_client : ContextClient): # pylint: disable=rede
def test_prepare_scenario(context_client : ContextClient): # pylint: disable=redefined-outer-name
# ----- Start the EventsCollector ----------------------------------------------------------------------------------
events_collector = EventsCollector(context_client)
events_collector.start()
#events_collector = EventsCollector(context_client)
#events_collector.start()
expected_events = []
#expected_events = []
# ----- Create Contexts and Topologies -----------------------------------------------------------------------------
for context in CONTEXTS:
......@@ -70,7 +70,7 @@ def test_prepare_scenario(context_client : ContextClient): # pylint: disable=re
LOGGER.info('Adding Context {:s}'.format(context_uuid))
response = context_client.SetContext(Context(**context))
assert response.context_uuid.uuid == context_uuid
expected_events.append(('ContextEvent', EVENT_CREATE, json_context_id(context_uuid)))
#expected_events.append(('ContextEvent', EVENT_CREATE, json_context_id(context_uuid)))
for topology in TOPOLOGIES:
context_uuid = topology['topology_id']['context_id']['context_uuid']['uuid']
......@@ -80,13 +80,13 @@ def test_prepare_scenario(context_client : ContextClient): # pylint: disable=re
assert response.context_id.context_uuid.uuid == context_uuid
assert response.topology_uuid.uuid == topology_uuid
context_id = json_context_id(context_uuid)
expected_events.append(('TopologyEvent', EVENT_CREATE, json_topology_id(topology_uuid, context_id=context_id)))
#expected_events.append(('TopologyEvent', EVENT_CREATE, json_topology_id(topology_uuid, context_id=context_id)))
# ----- Validate Collected Events ----------------------------------------------------------------------------------
check_events(events_collector, expected_events)
#check_events(events_collector, expected_events)
# ----- Stop the EventsCollector -----------------------------------------------------------------------------------
events_collector.stop()
#events_collector.stop()
def test_scenario_ready(context_client : ContextClient): # pylint: disable=redefined-outer-name
......@@ -111,10 +111,10 @@ def test_devices_bootstraping(
context_client : ContextClient, device_client : DeviceClient): # pylint: disable=redefined-outer-name
# ----- Start the EventsCollector ----------------------------------------------------------------------------------
events_collector = EventsCollector(context_client, log_events_received=True)
events_collector.start()
#events_collector = EventsCollector(context_client, log_events_received=True)
#events_collector.start()
expected_events = []
#expected_events = []
# ----- Create Devices and Validate Collected Events ---------------------------------------------------------------
for device, connect_rules in DEVICES:
......@@ -126,11 +126,11 @@ def test_devices_bootstraping(
response = device_client.AddDevice(Device(**device_with_connect_rules))
assert response.device_uuid.uuid == device_uuid
expected_events.extend([
# Device creation, update for automation to start the device
('DeviceEvent', EVENT_CREATE, json_device_id(device_uuid)),
#('DeviceEvent', EVENT_UPDATE, json_device_id(device_uuid)),
])
#expected_events.extend([
# # Device creation, update for automation to start the device
# ('DeviceEvent', EVENT_CREATE, json_device_id(device_uuid)),
# #('DeviceEvent', EVENT_UPDATE, json_device_id(device_uuid)),
#])
#response = context_client.GetDevice(response)
#for endpoint in response.device_endpoints:
......@@ -139,10 +139,10 @@ def test_devices_bootstraping(
# expected_events.append(('DeviceEvent', EVENT_UPDATE, json_device_id(device_uuid)))
# ----- Validate Collected Events ----------------------------------------------------------------------------------
check_events(events_collector, expected_events)
#check_events(events_collector, expected_events)
# ----- Stop the EventsCollector -----------------------------------------------------------------------------------
events_collector.stop()
#events_collector.stop()
def test_devices_bootstrapped(context_client : ContextClient): # pylint: disable=redefined-outer-name
......@@ -166,10 +166,10 @@ def test_devices_bootstrapped(context_client : ContextClient): # pylint: disabl
def test_links_creation(context_client : ContextClient): # pylint: disable=redefined-outer-name
# ----- Start the EventsCollector ----------------------------------------------------------------------------------
events_collector = EventsCollector(context_client)
events_collector.start()
#events_collector = EventsCollector(context_client)
#events_collector.start()
expected_events = []
#expected_events = []
# ----- Create Links and Validate Collected Events -----------------------------------------------------------------
for link in LINKS:
......@@ -177,13 +177,13 @@ def test_links_creation(context_client : ContextClient): # pylint: disable=rede
LOGGER.info('Adding Link {:s}'.format(link_uuid))
response = context_client.SetLink(Link(**link))
assert response.link_uuid.uuid == link_uuid
expected_events.append(('LinkEvent', EVENT_CREATE, json_link_id(link_uuid)))
#expected_events.append(('LinkEvent', EVENT_CREATE, json_link_id(link_uuid)))
# ----- Validate Collected Events ----------------------------------------------------------------------------------
check_events(events_collector, expected_events)
#check_events(events_collector, expected_events)
# ----- Stop the EventsCollector -----------------------------------------------------------------------------------
events_collector.stop()
#events_collector.stop()
def test_links_created(context_client : ContextClient): # pylint: disable=redefined-outer-name
......
......@@ -65,10 +65,10 @@ def test_scenario_cleanup(
context_client : ContextClient, device_client : DeviceClient): # pylint: disable=redefined-outer-name
# ----- Start the EventsCollector ----------------------------------------------------------------------------------
events_collector = EventsCollector(context_client)
events_collector.start()
#events_collector = EventsCollector(context_client)
#events_collector.start()
expected_events = []
#expected_events = []
# ----- Delete Links and Validate Collected Events -----------------------------------------------------------------
for link in LINKS:
......@@ -76,7 +76,7 @@ def test_scenario_cleanup(
link_uuid = link_id['link_uuid']['uuid']
LOGGER.info('Deleting Link {:s}'.format(link_uuid))
context_client.RemoveLink(LinkId(**link_id))
expected_events.append(('LinkEvent', EVENT_REMOVE, json_link_id(link_uuid)))
#expected_events.append(('LinkEvent', EVENT_REMOVE, json_link_id(link_uuid)))
# ----- Delete Devices and Validate Collected Events ---------------------------------------------------------------
for device, _ in DEVICES:
......@@ -84,7 +84,7 @@ def test_scenario_cleanup(
device_uuid = device_id['device_uuid']['uuid']
LOGGER.info('Deleting Device {:s}'.format(device_uuid))
device_client.DeleteDevice(DeviceId(**device_id))
expected_events.append(('DeviceEvent', EVENT_REMOVE, json_device_id(device_uuid)))
#expected_events.append(('DeviceEvent', EVENT_REMOVE, json_device_id(device_uuid)))
# ----- Delete Topologies and Validate Collected Events ------------------------------------------------------------
for topology in TOPOLOGIES:
......@@ -94,7 +94,7 @@ def test_scenario_cleanup(
LOGGER.info('Deleting Topology {:s}/{:s}'.format(context_uuid, topology_uuid))
context_client.RemoveTopology(TopologyId(**topology_id))
context_id = json_context_id(context_uuid)
expected_events.append(('TopologyEvent', EVENT_REMOVE, json_topology_id(topology_uuid, context_id=context_id)))
#expected_events.append(('TopologyEvent', EVENT_REMOVE, json_topology_id(topology_uuid, context_id=context_id)))
# ----- Delete Contexts and Validate Collected Events --------------------------------------------------------------
for context in CONTEXTS:
......@@ -102,13 +102,13 @@ def test_scenario_cleanup(
context_uuid = context_id['context_uuid']['uuid']
LOGGER.info('Deleting Context {:s}'.format(context_uuid))
context_client.RemoveContext(ContextId(**context_id))
expected_events.append(('ContextEvent', EVENT_REMOVE, json_context_id(context_uuid)))
#expected_events.append(('ContextEvent', EVENT_REMOVE, json_context_id(context_uuid)))
# ----- Validate Collected Events ----------------------------------------------------------------------------------
check_events(events_collector, expected_events)
#check_events(events_collector, expected_events)
# ----- Stop the EventsCollector -----------------------------------------------------------------------------------
events_collector.stop()
#events_collector.stop()
def test_scenario_empty_again(context_client : ContextClient): # pylint: disable=redefined-outer-name
......
......@@ -69,8 +69,8 @@ def test_scenario_is_correct(context_client : ContextClient): # pylint: disable
def test_service_creation(context_client : ContextClient, osm_wim : MockOSM): # pylint: disable=redefined-outer-name
# ----- Start the EventsCollector ----------------------------------------------------------------------------------
events_collector = EventsCollector(context_client, log_events_received=True)
events_collector.start()
#events_collector = EventsCollector(context_client, log_events_received=True)
#events_collector.start()
# ----- Create Service ---------------------------------------------------------------------------------------------
service_uuid = osm_wim.create_connectivity_service(WIM_SERVICE_TYPE, WIM_SERVICE_CONNECTION_POINTS)
......@@ -78,30 +78,30 @@ def test_service_creation(context_client : ContextClient, osm_wim : MockOSM): #
# ----- Validate collected events ----------------------------------------------------------------------------------
packet_connection_uuid = '{:s}:{:s}'.format(service_uuid, DEVTYPE_EMU_PR)
optical_connection_uuid = '{:s}:optical:{:s}'.format(service_uuid, DEVTYPE_EMU_OLS)
optical_service_uuid = '{:s}:optical'.format(service_uuid)
expected_events = [
# Create packet service and add first endpoint
('ServiceEvent', EVENT_CREATE, json_service_id(service_uuid, context_id=CONTEXT_ID)),
('ServiceEvent', EVENT_UPDATE, json_service_id(service_uuid, context_id=CONTEXT_ID)),
# Configure OLS controller, create optical service, create optical connection
('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_O1_UUID)),
('ServiceEvent', EVENT_CREATE, json_service_id(optical_service_uuid, context_id=CONTEXT_ID)),
('ConnectionEvent', EVENT_CREATE, json_connection_id(optical_connection_uuid)),
# Configure endpoint packet devices, add second endpoint to service, create connection
('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_R1_UUID)),
('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_R3_UUID)),
('ServiceEvent', EVENT_UPDATE, json_service_id(service_uuid, context_id=CONTEXT_ID)),
('ConnectionEvent', EVENT_CREATE, json_connection_id(packet_connection_uuid)),
]
check_events(events_collector, expected_events)
#packet_connection_uuid = '{:s}:{:s}'.format(service_uuid, DEVTYPE_EMU_PR)
#optical_connection_uuid = '{:s}:optical:{:s}'.format(service_uuid, DEVTYPE_EMU_OLS)
#optical_service_uuid = '{:s}:optical'.format(service_uuid)
#expected_events = [
# # Create packet service and add first endpoint
# ('ServiceEvent', EVENT_CREATE, json_service_id(service_uuid, context_id=CONTEXT_ID)),
# ('ServiceEvent', EVENT_UPDATE, json_service_id(service_uuid, context_id=CONTEXT_ID)),
#
# # Configure OLS controller, create optical service, create optical connection
# ('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_O1_UUID)),
# ('ServiceEvent', EVENT_CREATE, json_service_id(optical_service_uuid, context_id=CONTEXT_ID)),
# ('ConnectionEvent', EVENT_CREATE, json_connection_id(optical_connection_uuid)),
#
# # Configure endpoint packet devices, add second endpoint to service, create connection
# ('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_R1_UUID)),
# ('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_R3_UUID)),
# ('ServiceEvent', EVENT_UPDATE, json_service_id(service_uuid, context_id=CONTEXT_ID)),
# ('ConnectionEvent', EVENT_CREATE, json_connection_id(packet_connection_uuid)),
#]
#check_events(events_collector, expected_events)
# ----- Stop the EventsCollector -----------------------------------------------------------------------------------
events_collector.stop()
#events_collector.stop()
def test_scenario_service_created(context_client : ContextClient): # pylint: disable=redefined-outer-name
......
......@@ -23,7 +23,7 @@ from common.tools.grpc.Tools import grpc_message_to_json_string
from compute.tests.mock_osm.MockOSM import MockOSM
from context.client.ContextClient import ContextClient
from context.client.EventsCollector import EventsCollector
from common.proto.context_pb2 import ContextId, Empty
from common.proto.context_pb2 import ContextId, Empty, ServiceTypeEnum
from .Objects import (
CONTEXT_ID, CONTEXTS, DEVICE_O1_UUID, DEVICE_R1_UUID, DEVICE_R3_UUID, DEVICES, LINKS, TOPOLOGIES, WIM_MAPPING,
WIM_PASSWORD, WIM_USERNAME)
......@@ -77,43 +77,43 @@ def test_scenario_is_correct(context_client : ContextClient): # pylint: disable
def test_service_removal(context_client : ContextClient, osm_wim : MockOSM): # pylint: disable=redefined-outer-name
# ----- Start the EventsCollector ----------------------------------------------------------------------------------
events_collector = EventsCollector(context_client, log_events_received=True)
events_collector.start()
#events_collector = EventsCollector(context_client, log_events_received=True)
#events_collector.start()
# ----- Delete Service ---------------------------------------------------------------------------------------------
response = context_client.ListServiceIds(ContextId(**CONTEXT_ID))
LOGGER.info('Services[{:d}] = {:s}'.format(len(response.service_ids), grpc_message_to_json_string(response)))
assert len(response.service_ids) == 2 # L3NM + TAPI
response = context_client.ListServices(ContextId(**CONTEXT_ID))
LOGGER.info('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response)))
assert len(response.services) == 2 # L3NM + TAPI
service_uuids = set()
for service_id in response.service_ids:
service_uuid = service_id.service_uuid.uuid
if service_uuid.endswith(':optical'): continue
for service in response.services:
if service.service_type != ServiceTypeEnum.SERVICETYPE_L3NM: continue
service_uuid = service.service_id.service_uuid.uuid
service_uuids.add(service_uuid)
osm_wim.conn_info[service_uuid] = {}
assert len(service_uuids) == 1 # assume a single service has been created
assert len(service_uuids) == 1 # assume a single L3NM service has been created
service_uuid = set(service_uuids).pop()
osm_wim.delete_connectivity_service(service_uuid)
# ----- Validate collected events ----------------------------------------------------------------------------------
packet_connection_uuid = '{:s}:{:s}'.format(service_uuid, DEVTYPE_EMU_PR)
optical_connection_uuid = '{:s}:optical:{:s}'.format(service_uuid, DEVTYPE_EMU_OLS)
optical_service_uuid = '{:s}:optical'.format(service_uuid)
expected_events = [
('ConnectionEvent', EVENT_REMOVE, json_connection_id(packet_connection_uuid)),
('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_R1_UUID)),
('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_R3_UUID)),
('ServiceEvent', EVENT_REMOVE, json_service_id(service_uuid, context_id=CONTEXT_ID)),
('ConnectionEvent', EVENT_REMOVE, json_connection_id(optical_connection_uuid)),
('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_O1_UUID)),
('ServiceEvent', EVENT_REMOVE, json_service_id(optical_service_uuid, context_id=CONTEXT_ID)),
]
check_events(events_collector, expected_events)
#packet_connection_uuid = '{:s}:{:s}'.format(service_uuid, DEVTYPE_EMU_PR)
#optical_connection_uuid = '{:s}:optical:{:s}'.format(service_uuid, DEVTYPE_EMU_OLS)
#optical_service_uuid = '{:s}:optical'.format(service_uuid)
#expected_events = [
# ('ConnectionEvent', EVENT_REMOVE, json_connection_id(packet_connection_uuid)),
# ('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_R1_UUID)),
# ('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_R3_UUID)),
# ('ServiceEvent', EVENT_REMOVE, json_service_id(service_uuid, context_id=CONTEXT_ID)),
# ('ConnectionEvent', EVENT_REMOVE, json_connection_id(optical_connection_uuid)),
# ('DeviceEvent', EVENT_UPDATE, json_device_id(DEVICE_O1_UUID)),
# ('ServiceEvent', EVENT_REMOVE, json_service_id(optical_service_uuid, context_id=CONTEXT_ID)),
#]
#check_events(events_collector, expected_events)
# ----- Stop the EventsCollector -----------------------------------------------------------------------------------
events_collector.stop()
#events_collector.stop()
def test_services_removed(context_client : ContextClient): # pylint: disable=redefined-outer-name
......
......@@ -207,7 +207,19 @@
{{ connection.connection_id.connection_uuid.uuid }}
</td>
<td>
{{ connection.sub_service_ids|map(attribute='service_uuid')|map(attribute='uuid')|join(', ') }}
<ul>
{% for sub_service_id in connection.sub_service_ids %}
<li>
<a href="{{ url_for('service.detail', service_uuid=sub_service_id.service_uuid.uuid) }}">
{{ sub_service_id.service_uuid.uuid }}
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16">
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
<path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
</svg>
</a>
</li>
{% endfor %}
</ul>
</td>
{% for i in range(connection.path_hops_endpoint_ids|length) %}
......