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 604 additions and 17 deletions
# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
import logging
from analytics.database.Analyzer_DB import AnalyzerDB
LOGGER = logging.getLogger(__name__)
def test_verify_databases_and_tables():
LOGGER.info('>>> test_verify_databases_and_tables : START <<< ')
AnalyzerDBobj = AnalyzerDB()
# AnalyzerDBobj.drop_database()
# AnalyzerDBobj.verify_tables()
AnalyzerDBobj.create_database()
AnalyzerDBobj.create_tables()
AnalyzerDBobj.verify_tables()
<!-- Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
<!-- Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
......
<!-- Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
<!-- Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
......
<!-- Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
<!-- Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
......
......@@ -58,9 +58,16 @@ class ServiceNameEnum(Enum):
CACHING = 'caching'
TE = 'te'
FORECASTER = 'forecaster'
E2EORCHESTRATOR = 'e2eorchestrator'
E2EORCHESTRATOR = 'e2e-orchestrator'
OPTICALCONTROLLER = 'opticalcontroller'
BGPLS = 'bgpls-speaker'
KPIMANAGER = 'kpi-manager'
KPIVALUEAPI = 'kpi-value-api'
KPIVALUEWRITER = 'kpi-value-writer'
TELEMETRYFRONTEND = 'telemetry-frontend'
TELEMETRYBACKEND = 'telemetry-backend'
ANALYTICSFRONTEND = 'analytics-frontend'
ANALYTICSBACKEND = 'analytics-backend'
# Used for test and debugging only
DLT_GATEWAY = 'dltgateway'
......@@ -90,6 +97,13 @@ DEFAULT_SERVICE_GRPC_PORTS = {
ServiceNameEnum.E2EORCHESTRATOR .value : 10050,
ServiceNameEnum.OPTICALCONTROLLER .value : 10060,
ServiceNameEnum.BGPLS .value : 20030,
ServiceNameEnum.KPIMANAGER .value : 30010,
ServiceNameEnum.KPIVALUEAPI .value : 30020,
ServiceNameEnum.KPIVALUEWRITER .value : 30030,
ServiceNameEnum.TELEMETRYFRONTEND .value : 30050,
ServiceNameEnum.TELEMETRYBACKEND .value : 30060,
ServiceNameEnum.ANALYTICSFRONTEND .value : 30080,
ServiceNameEnum.ANALYTICSBACKEND .value : 30090,
# Used for test and debugging only
ServiceNameEnum.DLT_GATEWAY .value : 50051,
......
......@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging, os, time
import logging, os, re, time
from typing import Dict, List
from common.Constants import (
DEFAULT_GRPC_BIND_ADDRESS, DEFAULT_GRPC_GRACE_PERIOD, DEFAULT_GRPC_MAX_WORKERS, DEFAULT_HTTP_BIND_ADDRESS,
......@@ -68,7 +68,8 @@ def get_setting(name, **kwargs):
raise Exception('Setting({:s}) not specified in environment or configuration'.format(str(name)))
def get_env_var_name(service_name : ServiceNameEnum, env_var_group):
return ('{:s}SERVICE_{:s}'.format(service_name.value, env_var_group)).upper()
service_name = re.sub(r'[^a-zA-Z0-9]', '_', service_name.value)
return ('{:s}SERVICE_{:s}'.format(service_name, env_var_group)).upper()
def get_service_host(service_name : ServiceNameEnum):
envvar_name = get_env_var_name(service_name, ENVVAR_SUFIX_SERVICE_HOST)
......
# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
import logging
from enum import Enum
from confluent_kafka.admin import AdminClient, NewTopic
from common.Settings import get_setting
LOGGER = logging.getLogger(__name__)
KFK_SERVER_ADDRESS_TEMPLATE = 'kafka-service.{:s}.svc.cluster.local:{:s}'
class KafkaConfig(Enum):
@staticmethod
def get_kafka_address() -> str:
# kafka_server_address = get_setting('KFK_SERVER_ADDRESS', default=None)
# if kafka_server_address is None:
KFK_NAMESPACE = get_setting('KFK_NAMESPACE')
KFK_PORT = get_setting('KFK_SERVER_PORT')
kafka_server_address = KFK_SERVER_ADDRESS_TEMPLATE.format(KFK_NAMESPACE, KFK_PORT)
return kafka_server_address
@staticmethod
def get_admin_client():
SERVER_ADDRESS = KafkaConfig.get_kafka_address()
ADMIN_CLIENT = AdminClient({'bootstrap.servers': SERVER_ADDRESS })
return ADMIN_CLIENT
class KafkaTopic(Enum):
# TODO: Later to be populated from ENV variable.
REQUEST = 'topic_request'
RESPONSE = 'topic_response'
RAW = 'topic_raw'
LABELED = 'topic_labeled'
VALUE = 'topic_value'
ANALYTICS_REQUEST = 'topic_request_analytics'
ANALYTICS_RESPONSE = 'topic_response_analytics'
@staticmethod
def create_all_topics() -> bool:
"""
Method to create Kafka topics defined as class members
"""
all_topics = [member.value for member in KafkaTopic]
LOGGER.debug("Kafka server address is: {:} ".format(KafkaConfig.get_kafka_address()))
if( KafkaTopic.create_new_topic_if_not_exists( all_topics )):
LOGGER.debug("All topics are created sucsessfully or Already Exists")
return True
else:
LOGGER.debug("Error creating all topics")
return False
@staticmethod
def create_new_topic_if_not_exists(new_topics: list) -> bool:
"""
Method to create Kafka topic if it does not exist.
Args:
list of topic: containing the topic name(s) to be created on Kafka
"""
LOGGER.debug("Topics names to be verified and created: {:}".format(new_topics))
for topic in new_topics:
try:
topic_metadata = KafkaConfig.get_admin_client().list_topics(timeout=5)
# LOGGER.debug("Existing topic list: {:}".format(topic_metadata.topics))
if topic not in topic_metadata.topics:
# If the topic does not exist, create a new topic
print("Topic {:} does not exist. Creating...".format(topic))
LOGGER.debug("Topic {:} does not exist. Creating...".format(topic))
new_topic = NewTopic(topic, num_partitions=1, replication_factor=1)
KafkaConfig.get_admin_client().create_topics([new_topic])
else:
print("Topic name already exists: {:}".format(topic))
LOGGER.debug("Topic name already exists: {:}".format(topic))
except Exception as e:
LOGGER.debug("Failed to create topic: {:}".format(e))
return False
return True
# create all topics after the deployments (Telemetry and Analytics)
......@@ -23,7 +23,8 @@ Flask==2.1.3
Flask-HTTPAuth==4.5.0
Flask-RESTful==0.3.9
Jinja2==3.0.3
ncclient==0.6.13
numpy<2.0.0
ncclient==0.6.15
p4runtime==1.3.0
pandas==1.5.*
paramiko==2.9.2
......
......@@ -27,6 +27,9 @@ from .NetworkInstances import parse as parse_network_instances
from .RoutingPolicy import parse as parse_routing_policy
from .Acl import parse as parse_acl
from .Inventory import parse as parse_inventory
from .acl.acl_adapter import acl_cr_to_dict
from .acl.acl_adapter_ipinfusion_proprietary import acl_cr_to_dict_ipinfusion_proprietary
LOGGER = logging.getLogger(__name__)
ALL_RESOURCE_KEYS = [
......@@ -112,15 +115,32 @@ def compose_config( # template generation
]
elif (message_renderer == "jinja"):
templates =[]
template_name = '{:s}/edit_config.xml'.format(RE_REMOVE_FILTERS.sub('', resource_key))
templates.append(JINJA_ENV.get_template(template_name))
templates = []
if "acl_ruleset" in resource_key: # MANAGING ACLs
templates =[]
templates.append(JINJA_ENV.get_template('acl/acl-set/acl-entry/edit_config.xml'))
templates.append(JINJA_ENV.get_template('acl/interfaces/ingress/edit_config.xml'))
data : Dict[str, Any] = json.loads(resource_value)
if vendor == 'ipinfusion': # ipinfusion proprietary netconf receipe is used temporarily
enable_ingress_filter_path = 'acl/interfaces/ingress/enable_ingress_filter.xml'
acl_entry_path = 'acl/acl-set/acl-entry/edit_config_ipinfusion_proprietary.xml'
acl_ingress_path = 'acl/interfaces/ingress/edit_config_ipinfusion_proprietary.xml'
data : Dict[str, Any] = acl_cr_to_dict_ipinfusion_proprietary(resource_value, delete=delete)
else:
enable_ingress_filter_path = 'acl/interfaces/ingress/enable_ingress_filter.xml'
acl_entry_path = 'acl/acl-set/acl-entry/edit_config.xml'
acl_ingress_path = 'acl/interfaces/ingress/edit_config.xml'
data : Dict[str, Any] = acl_cr_to_dict(resource_value, delete=delete)
if delete: # unpair acl and interface before removing acl
templates.append(JINJA_ENV.get_template(acl_ingress_path))
templates.append(JINJA_ENV.get_template(acl_entry_path))
templates.append(JINJA_ENV.get_template(enable_ingress_filter_path))
else:
templates.append(JINJA_ENV.get_template(enable_ingress_filter_path))
templates.append(JINJA_ENV.get_template(acl_entry_path))
templates.append(JINJA_ENV.get_template(acl_ingress_path))
else:
template_name = '{:s}/edit_config.xml'.format(RE_REMOVE_FILTERS.sub('', resource_key))
templates.append(JINJA_ENV.get_template(template_name))
data : Dict[str, Any] = json.loads(resource_value)
operation = 'delete' if delete else 'merge' # others
#operation = 'delete' if delete else '' # ipinfusion?
......
# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
\ No newline at end of file
<acl xmlns="http://www.ipinfusion.com/yang/ocnos/ipi-acl">
<acl-sets>
<acl-set {% if operation == 'delete' %}operation="delete"{% endif %}>
<name>{{name}}</name>
{% if type is defined %}<type>{{type}}</type>{% endif %}
<config>
<name>{{name}}</name>
{% if type is defined %}<type>{{type}}</type>{% endif %}
</config>
{% if operation != 'delete' %}
<acl-entries>
<acl-entry>
<sequence-id>{{sequence_id}}</sequence-id>
<config>
<sequence-id>{{sequence_id}}</sequence-id>
</config>
<ipv4>
<config>
<source-address>{{source_address}}</source-address>
<destination-address>{{destination_address}}</destination-address>
<dscp>{{dscp}}</dscp>
<protocol-tcp />
<tcp-source-port>{{source_port}}</tcp-source-port>
<tcp-destination-port>{{destination_port}}</tcp-destination-port>
<tcp-flags>{{tcp_flags}}</tcp-flags>
<forwarding-action>{{forwarding_action}}</forwarding-action>
</config>
</ipv4>
</acl-entry>
</acl-entries>
{% endif %}
</acl-set>
</acl-sets>
</acl>
\ No newline at end of file
# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
from typing import Dict, TypedDict
from ..ACL.ACL_multivendor import RULE_TYPE_MAPPING, FORWARDING_ACTION_MAPPING, LOG_ACTION_MAPPING
class ACLRequestData(TypedDict):
name: str # acl-set name
type: str # acl-set type
sequence_id: int # acl-entry sequence-id
source_address: str
destination_address: str
forwarding_action: str
id: str # interface id
interface: str
subinterface: int
set_name_ingress: str # ingress-acl-set name
type_ingress: str # ingress-acl-set type
all: bool
dscp: int
protocol: int
tcp_flags: str
source_port: int
destination_port: int
def acl_cr_to_dict(acl_cr_dict: Dict, subinterface:int = 0) -> Dict:
rule_set = acl_cr_dict['rule_set']
rule_set_entry = rule_set['entries'][0]
rule_set_entry_match = rule_set_entry['match']
rule_set_entry_action = rule_set_entry['action']
name: str = rule_set['name']
type: str = RULE_TYPE_MAPPING[rule_set["type"]]
sequence_id = rule_set_entry['sequence_id']
source_address = rule_set_entry_match['src_address']
destination_address = rule_set_entry_match['dst_address']
forwarding_action: str = FORWARDING_ACTION_MAPPING[rule_set_entry_action['forward_action']]
interface_id = acl_cr_dict['interface']
interface = interface_id
set_name_ingress = name
type_ingress = type
return ACLRequestData(
name=name,
type=type,
sequence_id=sequence_id,
source_address=source_address,
destination_address=destination_address,
forwarding_action=forwarding_action,
id=interface_id,
interface=interface,
# subinterface=subinterface,
set_name_ingress=set_name_ingress,
type_ingress=type_ingress,
all=True,
dscp=18,
protocol=6,
tcp_flags='TCP_SYN',
source_port=22,
destination_port=80
)
# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
from typing import Dict, TypedDict
RULE_TYPE_MAPPING = {
'ACLRULETYPE_IPV4' : 'ip',
}
FORWARDING_ACTION_MAPPING = {
'ACLFORWARDINGACTION_DROP' : 'deny',
'ACLFORWARDINGACTION_ACCEPT' : 'permit',
}
class ACLRequestData(TypedDict):
name: str # acl-set name
type: str # acl-set type
sequence_id: int # acl-entry sequence-id
source_address: str
destination_address: str
forwarding_action: str
interface: str
dscp: int
tcp_flags: str
source_port: int
destination_port: int
def acl_cr_to_dict_ipinfusion_proprietary(acl_cr_dict: Dict, delete: bool = False) -> Dict:
rule_set = acl_cr_dict['rule_set']
name: str = rule_set['name']
type: str = RULE_TYPE_MAPPING[rule_set["type"]]
interface = acl_cr_dict['interface'][5:] # remove preceding `PORT-` characters
if delete:
return ACLRequestData(name=name, type=type, interface=interface)
rule_set_entry = rule_set['entries'][0]
rule_set_entry_match = rule_set_entry['match']
rule_set_entry_action = rule_set_entry['action']
return ACLRequestData(
name=name,
type=type,
sequence_id=rule_set_entry['sequence_id'],
source_address=rule_set_entry_match['src_address'],
destination_address=rule_set_entry_match['dst_address'],
forwarding_action=FORWARDING_ACTION_MAPPING[rule_set_entry_action['forward_action']],
interface=interface,
dscp=rule_set_entry_match["dscp"],
tcp_flags=rule_set_entry_match["flags"],
source_port=rule_set_entry_match['src_port'],
destination_port=rule_set_entry_match['dst_port']
)
<acl xmlns="http://www.ipinfusion.com/yang/ocnos/ipi-acl">
<interfaces>
<interface>
<name>{{interface}}</name>
<config>
<name>{{interface}}</name>
</config>
<ingress-acl-sets>
<ingress-acl-set {% if operation == "delete" %}operation="delete"{% endif %}>
{% if type is defined %}<acl-type>{{type}}</acl-type>{% endif %}
<access-groups>
<access-group>
<acl-name>{{name}}</acl-name>
<config>
<acl-name>{{name}}</acl-name>
</config>
</access-group>
</access-groups>
<config>
{% if type is defined %}<acl-type>{{type}}</acl-type>{% endif %}
</config>
</ingress-acl-set>
</ingress-acl-sets>
</interface>
</interfaces>
</acl>
\ No newline at end of file
<profiles xmlns="http://www.ipinfusion.com/yang/ocnos/ipi-platform">
<hardware-profile>
<filters>
<config>
<ingress-ipv4-extended {% if operation == "delete" %}operation="delete"{% endif %}></ingress-ipv4-extended>
</config>
</filters>
</hardware-profile>
</profiles>
\ No newline at end of file
/*
* Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
* Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
......
......@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#numpy==1.23.*
numpy<2.0.0
pandas==1.5.*
#prophet==1.1.*
scikit-learn==1.1.*
# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
# Build, tag, and push the Docker image to the GitLab Docker registry
build kpi-manager:
variables:
IMAGE_NAME: 'kpi_manager' # name of the microservice
IMAGE_TAG: 'latest' # tag of the container image (production, development, etc)
stage: build
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script:
- docker buildx build -t "$IMAGE_NAME:$IMAGE_TAG" -f ./src/$IMAGE_NAME/Dockerfile .
- docker tag "$IMAGE_NAME:$IMAGE_TAG" "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
- docker push "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
after_script:
- docker images --filter="dangling=true" --quiet | xargs -r docker rmi
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)'
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"'
- changes:
- src/common/**/*.py
- proto/*.proto
- src/$IMAGE_NAME/**/*.{py,in,yml}
- src/$IMAGE_NAME/Dockerfile
- src/$IMAGE_NAME/tests/*.py
- manifests/${IMAGE_NAME}service.yaml
- .gitlab-ci.yml
# Apply unit test to the component
unit_test kpi-manager:
variables:
IMAGE_NAME: 'kpi_manager' # name of the microservice
IMAGE_TAG: 'latest' # tag of the container image (production, development, etc)
stage: unit_test
needs:
- build kpi-manager
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
- if docker network list | grep teraflowbridge; then echo "teraflowbridge is already created"; else docker network create -d bridge teraflowbridge; fi
- if docker container ls | grep crdb; then docker rm -f crdb; else echo "CockroachDB container is not in the system"; fi
- if docker volume ls | grep crdb; then docker volume rm -f crdb; else echo "CockroachDB volume is not in the system"; fi
- if docker container ls | grep $IMAGE_NAME; then docker rm -f $IMAGE_NAME; else echo "$IMAGE_NAME container is not in the system"; fi
- docker container prune -f
script:
- docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
- docker pull "cockroachdb/cockroach:latest-v22.2"
- docker volume create crdb
- >
docker run --name crdb -d --network=teraflowbridge -p 26257:26257 -p 8080:8080
--env COCKROACH_DATABASE=tfs_test --env COCKROACH_USER=tfs --env COCKROACH_PASSWORD=tfs123
--volume "crdb:/cockroach/cockroach-data"
cockroachdb/cockroach:latest-v22.2 start-single-node
- echo "Waiting for initialization..."
- while ! docker logs crdb 2>&1 | grep -q 'finished creating default user \"tfs\"'; do sleep 1; done
- docker logs crdb
- docker ps -a
- CRDB_ADDRESS=$(docker inspect crdb --format "{{.NetworkSettings.Networks.teraflowbridge.IPAddress}}")
- echo $CRDB_ADDRESS
- >
docker run --name $IMAGE_NAME -d -p 30010:30010
--env "CRDB_URI=cockroachdb://tfs:tfs123@${CRDB_ADDRESS}:26257/tfs_test?sslmode=require"
--volume "$PWD/src/$IMAGE_NAME/tests:/opt/results"
--network=teraflowbridge
$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG
- docker ps -a
- sleep 5
- docker logs $IMAGE_NAME
- >
docker exec -i $IMAGE_NAME bash -c
"coverage run -m pytest --log-level=INFO --verbose --junitxml=/opt/results/${IMAGE_NAME}_report.xml $IMAGE_NAME/tests/test_*.py"
- docker exec -i $IMAGE_NAME bash -c "coverage report --include='${IMAGE_NAME}/*' --show-missing"
coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/'
after_script:
- docker volume rm -f crdb
- docker network rm teraflowbridge
- docker volume prune --force
- docker image prune --force
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)'
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"'
- changes:
- src/common/**/*.py
- proto/*.proto
- src/$IMAGE_NAME/**/*.{py,in,yml}
- src/$IMAGE_NAME/Dockerfile
- src/$IMAGE_NAME/tests/*.py
- src/$IMAGE_NAME/tests/Dockerfile
- manifests/${IMAGE_NAME}service.yaml
- .gitlab-ci.yml
artifacts:
when: always
reports:
junit: src/$IMAGE_NAME/tests/${IMAGE_NAME}_report.xml
## Deployment of the service in Kubernetes Cluster
#deploy context:
# variables:
# IMAGE_NAME: 'context' # name of the microservice
# IMAGE_TAG: 'latest' # tag of the container image (production, development, etc)
# stage: deploy
# needs:
# - unit test context
# # - integ_test execute
# script:
# - 'sed -i "s/$IMAGE_NAME:.*/$IMAGE_NAME:$IMAGE_TAG/" manifests/${IMAGE_NAME}service.yaml'
# - kubectl version
# - kubectl get all
# - kubectl apply -f "manifests/${IMAGE_NAME}service.yaml"
# - kubectl get all
# # environment:
# # name: test
# # url: https://example.com
# # kubernetes:
# # namespace: test
# rules:
# - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)'
# when: manual
# - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"'
# when: manual
# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (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.
FROM python:3.9-slim
# Install dependencies
RUN apt-get --yes --quiet --quiet update && \
apt-get --yes --quiet --quiet install wget g++ git && \
rm -rf /var/lib/apt/lists/*
# Set Python to show logs as they occur
ENV PYTHONUNBUFFERED=0
# Download the gRPC health probe
RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \
wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \
chmod +x /bin/grpc_health_probe
# Get generic Python packages
RUN python3 -m pip install --upgrade pip
RUN python3 -m pip install --upgrade setuptools wheel
RUN python3 -m pip install --upgrade pip-tools
# Get common Python packages
# Note: this step enables sharing the previous Docker build steps among all the Python components
WORKDIR /var/teraflow
COPY common_requirements.in common_requirements.in
RUN pip-compile --quiet --output-file=common_requirements.txt common_requirements.in
RUN python3 -m pip install -r common_requirements.txt
# Add common files into working directory
WORKDIR /var/teraflow/common
COPY src/common/. ./
RUN rm -rf proto
# Create proto sub-folder, copy .proto files, and generate Python code
RUN mkdir -p /var/teraflow/common/proto
WORKDIR /var/teraflow/common/proto
RUN touch __init__.py
COPY proto/*.proto ./
RUN python3 -m grpc_tools.protoc -I=. --python_out=. --grpc_python_out=. *.proto
RUN rm *.proto
RUN find . -type f -exec sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' {} \;
# Create component sub-folders, get specific Python packages
RUN mkdir -p /var/teraflow/kpi_manager
WORKDIR /var/teraflow/kpi_manager
COPY src/kpi_manager/requirements.in requirements.in
RUN pip-compile --quiet --output-file=requirements.txt requirements.in
RUN python3 -m pip install -r requirements.txt
# Add component files into working directory
WORKDIR /var/teraflow
COPY src/kpi_manager/. kpi_manager/
# Start the service
ENTRYPOINT ["python", "-m", "kpi_manager.service"]