Add support for httpGet liveness probes

Updates the locationservice, notificationservice and notificationclient
containers to support ipv6 httpGet liveness probes.

notificationservice-base and notificationservice-basev2:
- Adds health.py which starts a simple http server that runs within the
  daemon. The k8s httpGet liveness probe can query this endpoint to
  verify that the service is running
- Update the daemonset template and values to provide the required info
  for initalizing the new endpoint

locationservice-base:
- Remove unused portions of the locationservice_start.sh config map.
  The location-query-server.py and location-announce.py were never
  active and are not required
- Add locationservice_start.py in order to start the locationservice
  pecan WSGI application with either an ipv4 or ipv6 socket
- Use existing pecan endpoint to respond to liveness probes

notificationclient-base:
- Add notificationclient_start.py to start the notificationclient
  pecan WSGI application with either an ipv4 or ipv6 socket
- Use existing pecan endpoint to respond to liveness probes

Daemonset:
- Add required ip and port environment variables to support liveness
  probes on each container
- Add a conditional section for enabling liveness probes. Disabled by
  default but can be enabled via helm overrides by setting "liveness:
  True"

Misc:
- Re-organized python imports in affected files
- Incremented helm chart version to 2.0.1

Test-plan:
Pass: Verify application build and install
Pass: Verify containers build correctly
Pass: Deploy ptp-notification and verify basic sanity (v1 and v2 get,
subscribe, delete, list)
Pass: Enable httpGet liveness probes for each container and verify
operation
Pass: Verify application removal

Story: 2011090
Task: 49851

Signed-off-by: Cole Walker <cole.walker@windriver.com>
Change-Id: I4671c7f8c67c4869a6d5e3b384eae66d8c57a284
This commit is contained in:
Cole Walker 2024-04-05 12:40:53 -04:00
parent d38115c8ed
commit 37c15ea4fb
15 changed files with 421 additions and 197 deletions

4
.gitignore vendored
View File

@ -1,4 +1,6 @@
.tox
api-ref/build
doc/build
venv/
venv/
__pycache__/
*.pyc

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2021 Wind River Systems, Inc.
# Copyright (c) 2021-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -7,4 +7,4 @@ apiVersion: v1
appVersion: "2.0"
description: A Helm chart to deploy PTP Notification Service
name: ptp-notification
version: 2.0.0
version: 2.0.1

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2021 Wind River Systems, Inc.
# Copyright (c) 2021-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -18,124 +18,6 @@
# pip3 install oslo-config
# pip3 install oslo-messaging
cat <<EOF>/root/location-query-server.py
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import os
import json
import time # 引入time模块
import oslo_messaging
from oslo_config import cfg
THIS_NODE_NAME = os.environ.get("THIS_NODE_NAME",'controller-1')
THIS_POD_IP = os.environ.get("THIS_POD_IP",'127.0.0.1')
THIS_NAMESPACE = os.environ.get("THIS_NAMESPACE",'notification')
rabbituser = os.environ.get("REGISTRATION_USER",'admin')
rabbitpasswd = os.environ.get("REGISTRATION_PASS",'admin')
rabbitip = "registration.{0}.svc.cluster.local".format(THIS_NAMESPACE)
rabbitport = os.environ.get("REGISTRATION_PORT",'5672')
# 'rabbit://admin:admin@[127.0.0.1]:5672/'
# 'rabbit://admin:admin@[::1]:5672/'
rabbitendpoint = "rabbit://{0}:{1}@[{2}]:{3}".format(
rabbituser, rabbitpasswd, rabbitip, rabbitport)
class LocationInfoEndpoint(object):
target = oslo_messaging.Target(namespace='notification', version='1.0')
def __init__(self, server):
self.server = server
def QueryLocation(self, ctx, rpc_kwargs):
print ("QueryLocation called %s" %rpc_kwargs)
LocationInfo = {
'NodeName': THIS_NODE_NAME,
'PodIP': THIS_POD_IP,
'ResourceTypes': ['PTP'],
'Timestamp': time.time()
}
return LocationInfo
oslo_messaging.set_transport_defaults('notification_exchange')
transport = oslo_messaging.get_rpc_transport(cfg.CONF, url=rabbitendpoint)
target = oslo_messaging.Target(topic='LocationQuery', server="LocationService-{0}".format(THIS_NODE_NAME))
endpoints = [LocationInfoEndpoint(None)]
server = oslo_messaging.get_rpc_server(transport, target, endpoints,
executor=None)
# oslo_messaging.server.ExecutorLoadFailure:
# Failed to load executor "blocking": Executor should be None or 'eventlet' and 'threading'
server.start()
print("LocationService-{0} starts".format(THIS_NODE_NAME))
server.wait()
EOF
cat <<EOF>/root/location-announce.py
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import os
import json
import time # 引入time模块
import oslo_messaging
from oslo_config import cfg
from webob.exc import HTTPException, HTTPNotFound, HTTPBadRequest, HTTPClientError, HTTPServerError
THIS_NODE_NAME = os.environ.get("THIS_NODE_NAME",'controller-1')
THIS_POD_IP = os.environ.get("THIS_POD_IP",'127.0.0.1')
THIS_NAMESPACE = os.environ.get("THIS_NAMESPACE",'notification')
rabbituser = os.environ.get("REGISTRATION_USER",'admin')
rabbitpasswd = os.environ.get("REGISTRATION_PASS",'admin')
rabbitip = "registration.{0}.svc.cluster.local".format(THIS_NAMESPACE)
rabbitport = os.environ.get("REGISTRATION_PORT",'5672')
rabbitendpoint = "rabbit://{0}:{1}@[{2}]:{3}".format(
rabbituser, rabbitpasswd, rabbitip, rabbitport)
oslo_messaging.set_transport_defaults('notification_exchange')
transport = oslo_messaging.get_rpc_transport(cfg.CONF, url=rabbitendpoint)
location_topic='LocationListener-{0}'.format(THIS_NODE_NAME),
target = oslo_messaging.Target(
topic=location_topic,
fanout=True,
version='1.0', namespace='notification')
client = oslo_messaging.get_rpc_client(transport, target)
LocationInfo = {
'NodeName': THIS_NODE_NAME,
'PodIP': THIS_POD_IP,
'ResourceTypes': ['PTP'],
'Timestamp': time.time()
}
while True:
try:
client.cast({}, 'NotifyLocation', location_info=LocationInfo)
print("Announce location info:{0}@Topic:{1}".format(LocationInfo, location_topic))
except HTTPNotFound as ex:
print("Failed to publish location due to not found: {0}".format(str(ex)))
continue
except Exception as ex:
print("Failed to publish location due to: {0}".format(str(ex)))
continue
else:
break
EOF
echo "done"
# python3 /root/location-query-server.py &
# python3 /root/location-announce.py
cat <<EOF>/root/notification_control.py
import os
import time

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2021-2023 Wind River Systems, Inc.
# Copyright (c) 2021-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -88,10 +88,27 @@ spec:
value: "{{ .Values.notification.endpoint.pass }}"
- name: NOTIFICATIONSERVICE_PORT
value: "{{ .Values.notification.endpoint.port }}"
- name: LOCATION_SERVICE_HOST
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: LOCATION_SERVICE_PORT
value: "{{ .Values.location.endpoint.port }}"
- name: LOGGING_LEVEL
value: "{{ .Values.location.log_level }}"
command: ["/bin/bash", "/mnt/locationservice_start.sh"]
command: ["python3", "/opt/locationservice/locationservice_start.py"]
{{- if .Values.location.endpoint.liveness }}
livenessProbe:
failureThreshold: 3
httpGet:
path: /health
port: {{ .Values.location.endpoint.port }}
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 3
{{ end }}
volumeMounts:
- name: scripts
mountPath: /mnt
@ -136,6 +153,12 @@ spec:
value: "5672"
- name: REGISTRATION_HOST
value: "registration.{{.Values.global.namespace}}.svc.cluster.local"
- name: HEALTH_API_HOST
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: HEALTH_API_PORT
value: "{{ .Values.ptptrackingv2.endpoint.port }}"
- name: PTP4L_SERVICE_NAME
value: "{{ .Values.ptptrackingv2.ptp4lServiceName }}"
- name: PTP4L_CLOCK_CLASS_LOCKED_LIST
@ -153,6 +176,18 @@ spec:
- name: CONTROL_TIMEOUT
value: "{{ .Values.ptptrackingv2.control_timeout }}"
command: ["python3", "/mnt/ptptracking_start_v2.py"]
{{- if .Values.ptptrackingv2.endpoint.liveness }}
livenessProbe:
failureThreshold: 3
httpGet:
path: /health
port: {{ .Values.ptptrackingv2.endpoint.port }}
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 3
{{ end }}
securityContext:
privileged: true
capabilities:
@ -225,6 +260,12 @@ spec:
value: "5672"
- name: REGISTRATION_HOST
value: "registration.{{.Values.global.namespace}}.svc.cluster.local"
- name: HEALTH_API_HOST
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: HEALTH_API_PORT
value: "{{ .Values.ptptracking.endpoint.port }}"
- name: PTP4L_SERVICE_NAME
value: "{{ .Values.ptptracking.ptp4lServiceName }}"
- name: PTP4L_CLOCK_CLASS_LOCKED_LIST
@ -238,6 +279,18 @@ spec:
- name: LOGGING_LEVEL
value: "{{ .Values.ptptracking.logging_level }}"
command: ["python3", "/mnt/ptptracking_start.py"]
{{- if .Values.ptptracking.endpoint.liveness }}
livenessProbe:
failureThreshold: 3
httpGet:
path: /health
port: {{ .Values.ptptracking.endpoint.port }}
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 3
{{ end }}
securityContext:
privileged: true
capabilities:

View File

@ -63,6 +63,9 @@ notification:
location:
log_level: INFO
endpoint:
port: 8080
liveness: False
image:
repository: starlingx/locationservice-base
tag: stx.9.0-v2.2.0
@ -77,6 +80,9 @@ ptptracking:
phc2sysServiceName: phc2sys-legacy
phc2sysComSocket: False
logging_level: INFO
endpoint:
port: 8081
liveness: False
image:
repository: starlingx/notificationservice-base
tag: stx.9.0-v2.2.0
@ -96,6 +102,9 @@ ptptrackingv2:
phc2sysToleranceThreshold: 1000
ts2phcServiceName: True
log_level: INFO
endpoint:
port: 8082
liveness: False
image:
repository: starlingx/notificationservice-base-v2
tag: stx.9.0-v2.2.0

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2021 Wind River Systems, Inc.
# Copyright (c) 2021-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -11,12 +11,13 @@ server = {
}
# Pecan Application Configurations
# Ensure debug = False as per Pecan documentation
app = {
'root': 'apiserver.controllers.root.RootController',
'modules': ['apiserver'],
'static_root': '%(confdir)s/public',
'template_path': '%(confdir)s/apiserver/templates',
'debug': True,
'debug': False,
'errors': {
404: '/error/404',
'__force_dict__': True

View File

@ -0,0 +1,49 @@
#
# Copyright (c) 2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import logging
import os
import socket
from wsgiref import simple_server
from locationservicesdk.common.helpers import log_helper
from netaddr import IPAddress
from pecan.deploy import deploy
LOG = logging.getLogger(__name__)
log_helper.config_logger(LOG)
LOCATION_SERVICE_HOST = os.environ.get(
"LOCATION_SERVICE_HOST", '127.0.0.1')
LOCATION_SERVICE_PORT = int(
os.environ.get("LOCATION_SERVICE_PORT", '8080'))
def get_address_family(ip_string):
"""
Get the family for the given ip address string.
"""
ip_address = IPAddress(ip_string)
if ip_address.version == 6:
return socket.AF_INET6
else:
return socket.AF_INET
def main():
simple_server.WSGIServer.address_family = get_address_family(
LOCATION_SERVICE_HOST)
application = deploy('/opt/locationservice/config.py')
with simple_server.make_server(LOCATION_SERVICE_HOST,
LOCATION_SERVICE_PORT,
application) as httpd:
LOG.info("locationservice_start.py: Starting locationservice")
httpd.serve_forever()
if __name__ == "__main__":
main()

View File

@ -1,22 +1,21 @@
#
# Copyright (c) 2021 Wind River Systems, Inc.
# Copyright (c) 2021-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import os
import json
import time
import oslo_messaging
from oslo_config import cfg
from locationservicesdk.client.base import BrokerClientBase
import logging
import os
import time
import oslo_messaging
from locationservicesdk.client.base import BrokerClientBase
from locationservicesdk.common.helpers import log_helper
from oslo_config import cfg
LOG = logging.getLogger(__name__)
from locationservicesdk.common.helpers import log_helper
log_helper.config_logger(LOG)
@ -30,11 +29,12 @@ class LocationProducer(BrokerClientBase):
pass
def QueryLocation(self, ctx, **rpc_kwargs):
LOG.debug ("LocationProducer QueryLocation called %s" %rpc_kwargs)
LOG.debug("LocationProducer QueryLocation called %s" % rpc_kwargs)
return self.location_info
def TriggerAnnouncement(self, ctx, **rpc_kwargs):
LOG.debug ("LocationProducer TriggerAnnouncement called %s" %rpc_kwargs)
LOG.debug("LocationProducer TriggerAnnouncement called %s" %
rpc_kwargs)
if self.handler:
return self.handler.handle(**rpc_kwargs)
else:
@ -52,23 +52,26 @@ class LocationProducer(BrokerClientBase):
return
def announce_location(self, LocationInfo):
location_topic_all='LocationListener-*'
location_topic='LocationListener-{0}'.format(self.node_name)
location_topic_all = 'LocationListener-*'
location_topic = 'LocationListener-{0}'.format(self.node_name)
server = None
while True:
try:
self.cast(location_topic_all, 'NotifyLocation', location_info=LocationInfo)
LOG.debug("Broadcast location info:{0}@Topic:{1}".format(LocationInfo, location_topic))
self.cast(location_topic_all, 'NotifyLocation',
location_info=LocationInfo)
LOG.debug(
"Broadcast location info:{0}@Topic:{1}".format(LocationInfo, location_topic))
except Exception as ex:
LOG.debug("Failed to publish location due to: {0}".format(str(ex)))
LOG.debug(
"Failed to publish location due to: {0}".format(str(ex)))
continue
else:
break
def start_location_listener(self, location_info, handler=None):
topic='LocationQuery'
server="LocationService-{0}".format(self.node_name)
topic = 'LocationQuery'
server = "LocationService-{0}".format(self.node_name)
endpoints = [LocationProducer.ListenerEndpoint(location_info, handler)]
super(LocationProducer, self).add_listener(
@ -76,15 +79,13 @@ class LocationProducer(BrokerClientBase):
return True
def stop_location_listener(self):
topic='LocationQuery'
server="LocationService-{0}".format(self.node_name)
topic = 'LocationQuery'
server = "LocationService-{0}".format(self.node_name)
super(LocationProducer, self).remove_listener(
topic, server)
def is_listening(self):
topic='LocationQuery'
server="LocationService-{0}".format(self.node_name)
topic = 'LocationQuery'
server = "LocationService-{0}".format(self.node_name)
return super(LocationProducer, self).is_listening(
topic, server)

View File

@ -1,27 +1,32 @@
#
# Copyright (c) 2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import os
import json
import time
import oslo_messaging
from oslo_config import cfg
import logging
import multiprocessing as mp
import os
import time
from locationservicesdk.common.helpers import rpc_helper
from locationservicesdk.model.dto.rpc_endpoint import RpcEndpointInfo
from locationservicesdk.model.dto.resourcetype import ResourceType
import oslo_messaging
from locationservicesdk.client.locationproducer import LocationProducer
from locationservicesdk.common.helpers import log_helper, rpc_helper
from locationservicesdk.model.dto.resourcetype import ResourceType
from locationservicesdk.model.dto.rpc_endpoint import RpcEndpointInfo
from oslo_config import cfg
LOG = logging.getLogger(__name__)
from locationservicesdk.common.helpers import log_helper
log_helper.config_logger(LOG)
'''Entry point of Default Process Worker'''
def ProcessWorkerDefault(event, sqlalchemy_conf_json, registration_endpoint, location_info_json):
worker = LocationWatcherDefault(event, sqlalchemy_conf_json, registration_endpoint, location_info_json)
worker = LocationWatcherDefault(
event, sqlalchemy_conf_json, registration_endpoint, location_info_json)
worker.run()
return
@ -42,7 +47,8 @@ class LocationWatcherDefault:
self.location_info = json.loads(location_info_json)
this_node_name = self.location_info['NodeName']
self.registration_endpoint = RpcEndpointInfo(registration_transport_endpoint)
self.registration_endpoint = RpcEndpointInfo(
registration_transport_endpoint)
self.LocationProducer = LocationProducer(
this_node_name,
self.registration_endpoint.TransportEndpoint)
@ -67,18 +73,20 @@ class LocationWatcherDefault:
# max timeout: 1 hour
if self.event_timeout < float(3600):
self.event_timeout = self.event_timeout + self.event_timeout
LOG.debug("daemon control event is timeout")
LOG.debug("daemon control event is timeout: %s" %
self.event_timeout)
continue
self.__stop_listener()
'''Start listener to answer querying from clients'''
def __start_listener(self):
LOG.debug("start listener to answer location querying")
self.LocationProducer.start_location_listener(
self.location_info,
LocationWatcherDefault.LocationRequestHandlerDefault(self)
)
)
return
def __stop_listener(self):
@ -88,21 +96,25 @@ class LocationWatcherDefault:
return
'''announce location'''
def __announce_location(self):
LOG.debug("announce location info to clients")
self.LocationProducer.announce_location(self.location_info)
return
class DaemonControl(object):
def __init__(
self, sqlalchemy_conf_json, registration_transport_endpoint,
location_info, process_worker = None, daemon_mode=True):
self, sqlalchemy_conf_json, registration_transport_endpoint,
location_info, process_worker=None, daemon_mode=True):
self.daemon_mode = daemon_mode
self.event = mp.Event()
self.registration_endpoint = RpcEndpointInfo(registration_transport_endpoint)
self.registration_transport = rpc_helper.get_transport(self.registration_endpoint)
self.registration_endpoint = RpcEndpointInfo(
registration_transport_endpoint)
self.registration_transport = rpc_helper.get_transport(
self.registration_endpoint)
self.location_info = location_info
self.sqlalchemy_conf_json = sqlalchemy_conf_json
@ -116,8 +128,8 @@ class DaemonControl(object):
self.mpinstance = mp.Process(
target=process_worker,
args=(self.event, self.sqlalchemy_conf_json,
self.registration_endpoint.TransportEndpoint,
self.location_info))
self.registration_endpoint.TransportEndpoint,
self.location_info))
self.mpinstance.start()
pass

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2021 Wind River Systems, Inc.
# Copyright (c) 2021-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -17,12 +17,13 @@ server = {
}
# Pecan Application Configurations
# Ensure debug = False as per Pecan documentation
app = {
'root': 'sidecar.controllers.root.RootController',
'modules': ['sidecar'],
'static_root': '%(confdir)s/public',
'template_path': '%(confdir)s/sidecar/templates',
'debug': True,
'debug': False,
'errors': {
404: '/error/404',
'__force_dict__': True
@ -53,18 +54,18 @@ logging = {
'()': 'pecan.log.ColorFormatter',
'format': ('%(asctime)s [%(padded_color_levelname)s] [%(name)s]'
'[%(threadName)s] %(message)s'),
'__force_dict__': True
'__force_dict__': True
}
}
}
# Bindings and options to pass to SQLAlchemy's ``create_engine``
sqlalchemy = {
'url' : "sqlite:////{0}/sidecar.db".format(DATASTORE_PATH),
'echo' : False,
'echo_pool' : False,
'pool_recycle' : 3600,
'encoding' : 'utf-8'
'url': "sqlite:////{0}/sidecar.db".format(DATASTORE_PATH),
'echo': False,
'echo_pool': False,
'pool_recycle': 3600,
'encoding': 'utf-8'
}
# Custom Configurations must be in Python dictionary format::

View File

@ -0,0 +1,49 @@
#
# Copyright (c) 2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import logging
import os
import socket
from wsgiref import simple_server
from netaddr import IPAddress
from notificationclientsdk.common.helpers import log_helper
from pecan.deploy import deploy
LOG = logging.getLogger(__name__)
log_helper.config_logger(LOG)
SIDECAR_API_HOST = os.environ.get(
"SIDECAR_API_HOST", '127.0.0.1')
SIDECAR_API_PORT = int(
os.environ.get("SIDECAR_API_PORT", '8080'))
def get_address_family(ip_string):
"""
Get the family for the given ip address string.
"""
ip_address = IPAddress(ip_string)
if ip_address.version == 6:
return socket.AF_INET6
else:
return socket.AF_INET
def main():
simple_server.WSGIServer.address_family = get_address_family(
SIDECAR_API_HOST)
application = deploy('/opt/notificationclient/config.py')
with simple_server.make_server(SIDECAR_API_HOST,
SIDECAR_API_PORT,
application) as httpd:
LOG.info("notificationclient_start.py: Starting notificationclient")
httpd.serve_forever()
if __name__ == "__main__":
main()

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2021-2023 Wind River Systems, Inc.
# Copyright (c) 2021-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -10,21 +10,21 @@ import multiprocessing as mp
import os
import threading
import time
from oslo_utils import uuidutils
from oslo_utils import uuidutils
from trackingfunctionsdk.client.ptpeventproducer import PtpEventProducer
from trackingfunctionsdk.common.helpers import constants
from trackingfunctionsdk.common.helpers import constants, log_helper
from trackingfunctionsdk.common.helpers import ptpsync as utils
from trackingfunctionsdk.common.helpers import log_helper
from trackingfunctionsdk.common.helpers.gnss_monitor import GnssMonitor
from trackingfunctionsdk.common.helpers.os_clock_monitor import OsClockMonitor
from trackingfunctionsdk.common.helpers.ptp_monitor import PtpMonitor
from trackingfunctionsdk.model.dto.ptpstate import PtpState
from trackingfunctionsdk.model.dto.gnssstate import GnssState
from trackingfunctionsdk.model.dto.osclockstate import OsClockState
from trackingfunctionsdk.model.dto.overallclockstate import OverallClockState
from trackingfunctionsdk.model.dto.ptpstate import PtpState
from trackingfunctionsdk.model.dto.resourcetype import ResourceType
from trackingfunctionsdk.model.dto.rpc_endpoint import RpcEndpointInfo
from trackingfunctionsdk.services.health import HealthServer
LOG = logging.getLogger(__name__)
log_helper.config_logger(LOG)
@ -379,6 +379,10 @@ class PtpWatcherDefault:
# start location listener
self.__start_listener()
# Start the server for k8s httpGet health checks
notificationservice_health = HealthServer()
notificationservice_health.run()
while True:
# announce the location
forced = self.forced_publishing

View File

@ -0,0 +1,79 @@
#
# Copyright (c) 2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import json
import logging
import os
import socket
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
from netaddr import IPAddress
from pecan.deploy import deploy
from trackingfunctionsdk.common.helpers import log_helper
LOG = logging.getLogger(__name__)
log_helper.config_logger(LOG)
HEALTH_API_HOST = os.environ.get(
"HEALTH_API_HOST", '127.0.0.1')
HEALTH_API_PORT = int(
os.environ.get("HEALTH_API_PORT", '8082'))
def get_address_family(ip_string):
"""
Get the family for the given ip address string.
"""
ip_address = IPAddress(ip_string)
if ip_address.version == 6:
return socket.AF_INET6
else:
return socket.AF_INET
class HealthRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(self.get_response().encode("utf-8"))
def do_POST(self):
self.do_GET()
def get_response(self):
"""
Return a simple confirmation if the process is running.
Can be extended to check broader health aspects of notification service as needed
"""
return json.dumps(
{'health': True}
)
class HealthServer:
def __init__(self):
HTTPServer.address_family = get_address_family(HEALTH_API_HOST)
self.health_server = HTTPServer(
(HEALTH_API_HOST, HEALTH_API_PORT), HealthRequestHandler)
self.thread = threading.Thread(target=self.health_server.serve_forever)
self.thread.daemon = True
def run(self):
self.thread.start()
return
if __name__ == "__main__":
my_health = HealthServer()
my_health.run()
print(
f"Health server running on {HEALTH_API_HOST}:{str(HEALTH_API_PORT)}")
while True:
# run indefinitely
pass

View File

@ -1,31 +1,29 @@
#
# Copyright (c) 2021-2023 Wind River Systems, Inc.
# Copyright (c) 2021-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import os
import json
import logging
import multiprocessing as mp
import os
import threading
import time
import oslo_messaging
from oslo_config import cfg
import logging
import multiprocessing as mp
import threading
from trackingfunctionsdk.common.helpers import rpc_helper
from trackingfunctionsdk.model.dto.rpc_endpoint import RpcEndpointInfo
from trackingfunctionsdk.model.dto.resourcetype import ResourceType
from trackingfunctionsdk.model.dto.ptpstate import PtpState
from trackingfunctionsdk.client.ptpeventproducer import PtpEventProducer
from trackingfunctionsdk.common.helpers import ptpsync as ptpsync
from trackingfunctionsdk.model.dto.ptpstate import PtpState
from trackingfunctionsdk.model.dto.resourcetype import ResourceType
from trackingfunctionsdk.model.dto.rpc_endpoint import RpcEndpointInfo
from trackingfunctionsdk.services.health import HealthServer
LOG = logging.getLogger(__name__)
from trackingfunctionsdk.common.helpers import log_helper
log_helper.config_logger(LOG)
THIS_NODE_NAME = os.environ.get("THIS_NODE_NAME",'controller-0')
@ -115,6 +113,11 @@ class PtpWatcherDefault:
def run(self):
# start location listener
self.__start_listener()
# Start the server for k8s httpGet health checks
notificationservice_health = HealthServer()
notificationservice_health.run()
while True:
# annouce the location
forced = self.forced_publishing

View File

@ -0,0 +1,79 @@
#
# Copyright (c) 2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import json
import logging
import os
import socket
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
from netaddr import IPAddress
from pecan.deploy import deploy
from trackingfunctionsdk.common.helpers import log_helper
LOG = logging.getLogger(__name__)
log_helper.config_logger(LOG)
HEALTH_API_HOST = os.environ.get(
"HEALTH_API_HOST", '127.0.0.1')
HEALTH_SERVICE_API_PORT = int(
os.environ.get("HEALTH_API_PORT", '8081'))
def get_address_family(ip_string):
"""
Get the family for the given ip address string.
"""
ip_address = IPAddress(ip_string)
if ip_address.version == 6:
return socket.AF_INET6
else:
return socket.AF_INET
class HealthRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(self.get_response().encode("utf-8"))
def do_POST(self):
self.do_GET()
def get_response(self):
"""
Return a simple confirmation if the process is running.
Can be extended to check broader health aspects of notification service as needed
"""
return json.dumps(
{'health': True}
)
class HealthServer:
def __init__(self):
HTTPServer.address_family = get_address_family(HEALTH_API_HOST)
self.health_server = HTTPServer(
(HEALTH_API_HOST, HEALTH_SERVICE_API_PORT), HealthRequestHandler)
self.thread = threading.Thread(target=self.health_server.serve_forever)
self.thread.daemon = True
def run(self):
self.thread.start()
return
if __name__ == "__main__":
my_health = HealthServer()
my_health.run()
print(
f"Health server running on {HEALTH_API_HOST}:{str(HEALTH_SERVICE_API_PORT)}")
while True:
# run indefinitely
pass