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
Showing
with 354 additions and 62 deletions
......@@ -37,6 +37,8 @@ spec:
env:
- name: LOG_LEVEL
value: "INFO"
- name: ENABLE_FORECASTER
value: "YES"
readinessProbe:
exec:
command: ["/bin/grpc_health_probe", "-addr=:10020"]
......
......@@ -277,9 +277,9 @@ apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
namespace: monitoring # namespace where prometheus is running
name: tfs-automationservice-metric
name: tfs-ztpservice-metric
labels:
app: automationservice
app: ztpservice
#release: prometheus
#release: prom # name of the release
# ( VERY IMPORTANT: You need to know the correct release name by viewing
......@@ -290,7 +290,7 @@ spec:
matchLabels:
# Target app service
#namespace: tfs
app: automationservice # same as above
app: ztpservice # same as above
#release: prometheus # same as above
endpoints:
- port: metrics # named port in target app
......@@ -306,9 +306,9 @@ apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
namespace: monitoring # namespace where prometheus is running
name: tfs-computeservice-metric
name: tfs-nbiservice-metric
labels:
app: computeservice
app: nbiservice
#release: prometheus
#release: prom # name of the release
# ( VERY IMPORTANT: You need to know the correct release name by viewing
......@@ -319,7 +319,7 @@ spec:
matchLabels:
# Target app service
#namespace: tfs
app: computeservice # same as above
app: nbiservice # same as above
#release: prometheus # same as above
endpoints:
- port: metrics # named port in target app
......@@ -474,4 +474,4 @@ spec:
namespaceSelector:
any: false
matchNames:
- tfs # namespace where the app is running
\ No newline at end of file
- tfs # namespace where the app is running
......@@ -74,26 +74,27 @@ spec:
- name: GF_SERVER_SERVE_FROM_SUB_PATH
value: "true"
readinessProbe:
failureThreshold: 3
failureThreshold: 60
httpGet:
path: /robots.txt
#path: /robots.txt
path: /login
port: 3000
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 30
initialDelaySeconds: 1
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 2
livenessProbe:
failureThreshold: 3
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 60
initialDelaySeconds: 1
periodSeconds: 1
successThreshold: 1
tcpSocket:
port: 3000
timeoutSeconds: 1
resources:
requests:
cpu: 150m
cpu: 250m
memory: 512Mi
limits:
cpu: 500m
......
......@@ -19,9 +19,9 @@ metadata:
annotations:
app.quarkus.io/build-timestamp: 2022-09-19 - 10:48:18 +0000
labels:
app.kubernetes.io/name: automationservice
app: automationservice
name: automationservice
app.kubernetes.io/name: ztpservice
app: ztpservice
name: ztpservice
spec:
ports:
- name: grpc
......@@ -32,7 +32,7 @@ spec:
port: 9192
targetPort: 8080
selector:
app.kubernetes.io/name: automationservice
app.kubernetes.io/name: ztpservice
type: ClusterIP
---
apiVersion: apps/v1
......@@ -41,21 +41,21 @@ metadata:
annotations:
app.quarkus.io/build-timestamp: 2022-09-19 - 10:48:18 +0000
labels:
app: automationservice
app.kubernetes.io/name: automationservice
name: automationservice
app: ztpservice
app.kubernetes.io/name: ztpservice
name: ztpservice
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: automationservice
app.kubernetes.io/name: ztpservice
template:
metadata:
annotations:
app.quarkus.io/build-timestamp: 2022-09-19 - 10:48:18 +0000
labels:
app: automationservice
app.kubernetes.io/name: automationservice
app: ztpservice
app.kubernetes.io/name: ztpservice
spec:
containers:
- env:
......@@ -67,7 +67,7 @@ spec:
value: contextservice
- name: DEVICE_SERVICE_HOST
value: deviceservice
image: labs.etsi.org:5050/tfs/controller/automation:0.2.0
image: labs.etsi.org:5050/tfs/controller/ztp:0.2.0
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
......@@ -79,7 +79,7 @@ spec:
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 10
name: automationservice
name: ztpservice
ports:
- containerPort: 5050
name: grpc
......@@ -108,12 +108,12 @@ spec:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: automationservice-hpa
name: ztpservice-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: automationservice
name: ztpservice
minReplicas: 1
maxReplicas: 10
metrics:
......
......@@ -20,13 +20,22 @@
export TFS_REGISTRY_IMAGES="http://localhost:32000/tfs/"
# Set the list of components, separated by spaces, you want to build images for, and deploy.
export TFS_COMPONENTS="context device pathcomp service slice compute webui load_generator"
export TFS_COMPONENTS="context device pathcomp service slice nbi webui load_generator"
# Uncomment to activate Monitoring
#export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring"
# Uncomment to activate Automation and Policy Manager
#export TFS_COMPONENTS="${TFS_COMPONENTS} automation policy"
# Uncomment to activate BGP-LS Speaker
#export TFS_COMPONENTS="${TFS_COMPONENTS} bgpls_speaker"
# Uncomment to activate Optical Controller
#export TFS_COMPONENTS="${TFS_COMPONENTS} opticalcontroller"
# Uncomment to activate ZTP
#export TFS_COMPONENTS="${TFS_COMPONENTS} ztp"
# Uncomment to activate Policy Manager
#export TFS_COMPONENTS="${TFS_COMPONENTS} policy"
# Uncomment to activate Optical CyberSecurity
#export TFS_COMPONENTS="${TFS_COMPONENTS} dbscanserving opticalattackmitigator opticalattackdetector opticalattackmanager"
......@@ -37,6 +46,12 @@ export TFS_COMPONENTS="context device pathcomp service slice compute webui load_
# Uncomment to activate TE
#export TFS_COMPONENTS="${TFS_COMPONENTS} te"
# Uncomment to activate Forecaster
#export TFS_COMPONENTS="${TFS_COMPONENTS} forecaster"
# Uncomment to activate E2E Orchestrator
#export TFS_COMPONENTS="${TFS_COMPONENTS} e2e_orchestrator"
# Set the tag you want to use for your images.
export TFS_IMAGE_TAG="dev"
......
src/tests/ofc24/
\ No newline at end of file
// Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
//
// 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.
syntax = "proto3";
package bgpls;
import "context.proto";
service BgplsService {
rpc ListDiscoveredDevices (context.Empty ) returns (DiscoveredDeviceList) {}
rpc ListDiscoveredLinks (context.Empty ) returns (DiscoveredLinkList ) {}
rpc AddBgplsSpeaker (BgplsSpeaker ) returns (BgplsSpeakerId ) {}
rpc ListBgplsSpeakers (context.Empty ) returns (BgplsSpeakerList ) {}
rpc DisconnectFromSpeaker (BgplsSpeaker ) returns (context.Empty ) {}
rpc GetSpeakerInfoFromId (BgplsSpeakerId ) returns (BgplsSpeaker ) {}
rpc NotifyAddNodeToContext(NodeDescriptors) returns (context.Empty ) {}
}
message DiscoveredDevice {
string nodeName = 1;
string ip = 2;
string igpID = 3;
string learntFrom = 4;
}
message DiscoveredDeviceList {
repeated DiscoveredDevice discovereddevices = 1;
}
message DiscoveredLinkList{
repeated DiscoveredLink discoveredlinks = 1;
}
message DiscoveredLink{
NodeDescriptors local = 1;
NodeDescriptors remote = 2;
string learntFrom = 3;
string local_ipv4 = 4;
string remote_ipv4 = 5;
}
message NodeDescriptors{
string asNumber = 1;
string igp_id = 2;
string nodeName = 3;
}
message BgplsSpeaker{
string address = 1;
string port = 2;
string asNumber = 3;
}
message BgplsSpeakerId{
uint32 id = 1;
}
message BgplsSpeakerList{
repeated BgplsSpeakerId speakers = 1;
}
......@@ -74,6 +74,16 @@ service ContextService {
rpc SetConnection (Connection ) returns ( ConnectionId ) {}
rpc RemoveConnection (ConnectionId ) returns ( Empty ) {}
rpc GetConnectionEvents(Empty ) returns (stream ConnectionEvent ) {}
// ------------------------------ Experimental -----------------------------
rpc GetOpticalConfig (Empty ) returns (OpticalConfigList ) {}
rpc SetOpticalConfig (OpticalConfig ) returns (OpticalConfigId ) {}
rpc SelectOpticalConfig(OpticalConfigId) returns (OpticalConfig ) {}
rpc SetOpticalLink (OpticalLink ) returns (Empty ) {}
rpc GetOpticalLink (OpticalLinkId ) returns (OpticalLink ) {}
rpc GetFiber (FiberId ) returns (Fiber ) {}
}
// ----- Generic -------------------------------------------------------------------------------------------------------
......@@ -174,12 +184,17 @@ message Device {
DeviceOperationalStatusEnum device_operational_status = 5;
repeated DeviceDriverEnum device_drivers = 6;
repeated EndPoint device_endpoints = 7;
repeated Component component = 8; // Used for inventory
repeated Component components = 8; // Used for inventory
DeviceId controller_id = 9; // Identifier of node controlling the actual device
}
message Component {
repeated string comp_string = 1;
message Component { //Defined previously to this section - Tested OK
Uuid component_uuid = 1;
string name = 2;
string type = 3;
map<string, string> attributes = 4; // dict[attr.name => json.dumps(attr.value)]
string parent = 5;
}
message DeviceConfig {
......@@ -192,10 +207,13 @@ enum DeviceDriverEnum {
DEVICEDRIVER_TRANSPORT_API = 2;
DEVICEDRIVER_P4 = 3;
DEVICEDRIVER_IETF_NETWORK_TOPOLOGY = 4;
DEVICEDRIVER_ONF_TR_352 = 5;
DEVICEDRIVER_ONF_TR_532 = 5;
DEVICEDRIVER_XR = 6;
DEVICEDRIVER_IETF_L2VPN = 7;
DEVICEDRIVER_GNMI_OPENCONFIG = 8;
DEVICEDRIVER_FLEXSCALE = 9;
DEVICEDRIVER_IETF_ACTN = 10;
DEVICEDRIVER_OC = 11;
}
enum DeviceOperationalStatusEnum {
......@@ -231,10 +249,16 @@ message LinkId {
Uuid link_uuid = 1;
}
message LinkAttributes {
float total_capacity_gbps = 1;
float used_capacity_gbps = 2;
}
message Link {
LinkId link_id = 1;
string name = 2;
repeated EndPointId link_endpoint_ids = 3;
LinkAttributes attributes = 4;
}
message LinkIdList {
......@@ -274,6 +298,8 @@ enum ServiceTypeEnum {
SERVICETYPE_L2NM = 2;
SERVICETYPE_TAPI_CONNECTIVITY_SERVICE = 3;
SERVICETYPE_TE = 4;
SERVICETYPE_E2E = 5;
SERVICETYPE_OPTICAL_CONNECTIVITY = 6;
}
enum ServiceStatusEnum {
......@@ -598,3 +624,53 @@ message AuthenticationResult {
ContextId context_id = 1;
bool authenticated = 2;
}
// ---------------- Experimental ------------------------
message OpticalConfigId {
string opticalconfig_uuid = 1;
}
message OpticalConfig {
OpticalConfigId opticalconfig_id = 1;
string config = 2;
}
message OpticalConfigList {
repeated OpticalConfig opticalconfigs = 1;
}
// ---- Optical Link ----
message OpticalLinkId {
Uuid optical_link_uuid = 1;
}
message FiberId {
Uuid fiber_uuid = 1;
}
message Fiber {
string ID = 10;
string src_port = 1;
string dst_port = 2;
string local_peer_port = 3;
string remote_peer_port = 4;
repeated int32 c_slots = 5;
repeated int32 l_slots = 6;
repeated int32 s_slots = 7;
float length = 8;
bool used = 9;
FiberId fiber_uuid = 11;
}
message OpticalLinkDetails {
float length = 1;
string source = 2;
string target = 3;
repeated Fiber fibers = 4;
}
message OpticalLink {
string name = 1;
OpticalLinkDetails details = 2;
OpticalLinkId optical_link_uuid = 3;
}
// Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
//
// 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.
// protocol buffers documentation: https://developers.google.com/protocol-buffers/docs/proto3
syntax = "proto3";
package orchestrator;
import "context.proto";
service E2EOrchestratorService {
rpc Compute(E2EOrchestratorRequest) returns (E2EOrchestratorReply) {}
}
message E2EOrchestratorRequest {
context.Service service = 1;
}
message E2EOrchestratorReply {
// Service requested completed with possible missing fields, and
// sub-services required for supporting requested service on the
// underlying layers.
repeated context.Service services = 1;
// Connections supporting the requested service and sub-services
// required for the underlying layers.
repeated context.Connection connections = 2;
}
\ No newline at end of file
......@@ -18,28 +18,27 @@ package forecaster;
import "context.proto";
service ForecasterService {
rpc GetForecastOfTopology (context.TopologyId) returns (Forecast) {}
rpc GetForecastOfLink(context.LinkId) returns (Forecast) {}
rpc CheckService (context.ServiceId) returns (ForecastPrediction) {}
rpc ForecastLinkCapacity (ForecastLinkCapacityRequest ) returns (ForecastLinkCapacityReply ) {}
rpc ForecastTopologyCapacity(ForecastTopologyCapacityRequest) returns (ForecastTopologyCapacityReply) {}
}
message SingleForecast {
context.Timestamp timestamp= 1;
double value = 2;
message ForecastLinkCapacityRequest {
context.LinkId link_id = 1;
float forecast_window_seconds = 2;
}
message Forecast {
oneof uuid {
context.TopologyId topologyId= 1;
context.LinkId linkId = 2;
}
repeated SingleForecast forecast = 3;
message ForecastLinkCapacityReply {
context.LinkId link_id = 1;
float total_capacity_gbps = 2;
float current_used_capacity_gbps = 3;
float forecast_used_capacity_gbps = 4;
}
enum AvailabilityPredictionEnum {
FORECASTED_AVAILABILITY = 0;
FORECASTED_UNAVAILABILITY = 1;
message ForecastTopologyCapacityRequest {
context.TopologyId topology_id = 1;
float forecast_window_seconds = 2;
}
message ForecastPrediction {
AvailabilityPredictionEnum prediction = 1;
message ForecastTopologyCapacityReply {
repeated ForecastLinkCapacityReply link_capacities = 1;
}
#!/bin/bash -eu
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# 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.
export JAVA_COMPONENTS="ztp policy"
export TFS_ROOT_DIR=$(dirname $(dirname $(realpath $0)))
for COMPONENT in $JAVA_COMPONENTS; do
echo "\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/"
echo
echo "[TFS] Now building" $COMPONENT
echo
echo "\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/"
cd $TFS_ROOT_DIR/src/$COMPONENT
./mvnw spotless:apply
./mvnw install -DskipUTs
done
......@@ -17,18 +17,26 @@ package kpi_sample_types;
enum KpiSampleType {
KPISAMPLETYPE_UNKNOWN = 0;
KPISAMPLETYPE_PACKETS_TRANSMITTED = 101;
KPISAMPLETYPE_PACKETS_RECEIVED = 102;
KPISAMPLETYPE_PACKETS_DROPPED = 103;
KPISAMPLETYPE_BYTES_TRANSMITTED = 201;
KPISAMPLETYPE_BYTES_RECEIVED = 202;
KPISAMPLETYPE_BYTES_DROPPED = 203;
KPISAMPLETYPE_LINK_TOTAL_CAPACITY_GBPS = 301;
KPISAMPLETYPE_LINK_USED_CAPACITY_GBPS = 302;
KPISAMPLETYPE_ML_CONFIDENCE = 401; //. can be used by both optical and L3 without any issue
KPISAMPLETYPE_OPTICAL_SECURITY_STATUS = 501; //. can be used by both optical and L3 without any issue
KPISAMPLETYPE_L3_UNIQUE_ATTACK_CONNS = 601;
KPISAMPLETYPE_L3_TOTAL_DROPPED_PACKTS = 602;
KPISAMPLETYPE_L3_UNIQUE_ATTACKERS = 603;
KPISAMPLETYPE_L3_UNIQUE_COMPROMISED_CLIENTS = 604;
KPISAMPLETYPE_L3_SECURITY_STATUS_CRYPTO = 605;
KPISAMPLETYPE_SERVICE_LATENCY_MS = 701;
}
......@@ -49,6 +49,7 @@ message KpiDescriptor {
context.ServiceId service_id = 7;
context.SliceId slice_id = 8;
context.ConnectionId connection_id = 9;
context.LinkId link_id = 10;
}
message MonitorKpiRequest {
......
......@@ -13,11 +13,11 @@
// limitations under the License.
syntax = "proto3";
package compute;
package nbi;
import "context.proto";
service ComputeService {
service NbiService {
rpc CheckCredentials (context.TeraFlowController) returns (context.AuthenticationResult) {}
rpc GetConnectivityServiceStatus (context.ServiceId ) returns (context.ServiceStatus ) {}
rpc CreateConnectivityService (context.Service ) returns (context.ServiceId ) {}
......
// Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
//
// 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.
syntax = "proto3";
package openconfig_device;
import "context.proto";
service OpenConfigService {
rpc AddOpenConfigDevice (context.OpticalConfig) returns (context.OpticalConfigId) {}
rpc ConfigureOpticalDevice(context.OpticalConfig) returns (context.Empty ) {}
}
......@@ -13,11 +13,11 @@
// limitations under the License.
syntax = "proto3";
package automation;
package ztp;
import "context.proto";
service AutomationService {
service ZtpService {
rpc ZtpGetDeviceRole(DeviceRoleId) returns (DeviceRole) {}
rpc ZtpGetDeviceRolesByDeviceId(context.DeviceId) returns (DeviceRoleList) {}
rpc ZtpAdd(DeviceRole) returns (DeviceRoleState) {}
......
......@@ -24,7 +24,7 @@ REGISTRY_IMAGE=""
#REGISTRY_IMAGE="http://my-container-registry.local/"
# Set the list of components you want to build images for, and deploy.
COMPONENTS="context device automation policy service compute monitoring centralizedattackdetector"
COMPONENTS="context device ztp policy service nbi monitoring centralizedattackdetector"
# Set the tag you want to use for your images.
IMAGE_TAG="tf-dev"
......@@ -43,7 +43,7 @@ for COMPONENT in $COMPONENTS; do
echo " Building Docker image..."
BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}.log"
if [ "$COMPONENT" == "automation" ] || [ "$COMPONENT" == "policy" ]; then
if [ "$COMPONENT" == "ztp" ] || [ "$COMPONENT" == "policy" ]; then
docker build -t "$IMAGE_NAME" -f ./src/"$COMPONENT"/Dockerfile ./src/"$COMPONENT"/ > "$BUILD_LOG"
else
docker build -t "$IMAGE_NAME" -f ./src/"$COMPONENT"/Dockerfile ./src/ > "$BUILD_LOG"
......
......@@ -24,7 +24,7 @@ export REGISTRY_IMAGE=${REGISTRY_IMAGE:-""}
#export REGISTRY_IMAGE="http://my-container-registry.local/"
# If not already set, set the list of components you want to build images for, and deploy.
export COMPONENTS=${COMPONENTS:-"context device automation policy service compute monitoring dbscanserving opticalattackmitigator opticalcentralizedattackdetector webui"}
export COMPONENTS=${COMPONENTS:-"context device ztp policy service nbi monitoring dbscanserving opticalattackmitigator opticalcentralizedattackdetector webui"}
# If not already set, set the tag you want to use for your images.
export IMAGE_TAG=${IMAGE_TAG:-"tf-dev"}
......@@ -78,7 +78,7 @@ for COMPONENT in $COMPONENTS; do
echo " Building Docker image..."
BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}.log"
if [ "$COMPONENT" == "automation" ] || [ "$COMPONENT" == "policy" ]; then
if [ "$COMPONENT" == "ztp" ] || [ "$COMPONENT" == "policy" ]; then
docker build -t "$IMAGE_NAME" -f ./src/"$COMPONENT"/Dockerfile ./src/"$COMPONENT"/ > "$BUILD_LOG"
else
docker build -t "$IMAGE_NAME" -f ./src/"$COMPONENT"/Dockerfile . > "$BUILD_LOG"
......
......@@ -14,4 +14,4 @@
# limitations under the License.
./report_coverage_all.sh | grep --color -E -i "^compute/.*$|$"
./report_coverage_all.sh | grep --color -E -i "^nbi/.*$|$"
#!/bin/bash
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# 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.
PROJECTDIR=`pwd`
cd $PROJECTDIR/src
RCFILE=$PROJECTDIR/coverage/.coveragerc
# Run unitary tests and analyze coverage of code at same time
# helpful pytest flags: --log-level=INFO -o log_cli=true --verbose --maxfail=1 --durations=0
coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
device/tests/test_unitary_ietf_actn.py