Implement health check for xApp 71/9671/3
authorsubhash kumar singh <subh.singh@samsung.com>
Wed, 16 Nov 2022 18:02:21 +0000 (18:02 +0000)
committersubhash kumar singh <subh.singh@samsung.com>
Thu, 24 Nov 2022 10:14:20 +0000 (10:14 +0000)
Implement API to query the health status of xApp.

Signed-off-by: subhash kumar singh <subh.singh@samsung.com>
Change-Id: Ie0b922fa72af9d174766e8cf947cebfc4aa3ec76

config/config-test.yaml
config/config.yaml
pkg/config/conf.go
pkg/health/health.go
pkg/restful/restful.go
pkg/resthooks/resthooks.go
pkg/resthooks/resthooks_test.go

index b2b2461..4b41e89 100644 (file)
@@ -18,4 +18,5 @@ mock-server: "127.0.0.1:9191"
 getCharts-url: "http://127.0.0.1:9191"
 download-charts-url-format: "http://127.0.0.1:9191/helmrepo/charts/%s-%s.tgz"
 getCharts-by-name-url: "http://127.0.0.1:9191/helmrepo/api/charts/%s"
-getCharts-by-name-and-version-url: "http://127.0.0.1:9191/helmrepo/api/charts/%s/%s"
\ No newline at end of file
+getCharts-by-name-and-version-url: "http://127.0.0.1:9191/helmrepo/api/charts/%s/%s"
+getXappHealth-url: "http://127.0.0.1:9191/ric/v1/health/alive/%s/%s"
\ No newline at end of file
index 861912d..36604be 100644 (file)
@@ -17,4 +17,5 @@ onborder-url: "http://service-ricplt-xapp-onboarder-http.ricplt:8888/api/v1/onbo
 getCharts-url: "http://service-ricplt-xapp-onboarder-http.ricplt:8080/api/charts"
 download-charts-url-format: "http://service-ricplt-xapp-onboarder-http.ricplt:8080/charts/%s-%s.tgz"
 getCharts-by-name-url: "http://172.17.0.1:9100/helmrepo/api/charts/%s"
-getCharts-by-name-and-version-url: "http://172.17.0.1:9100/helmrepo/api/charts/%s/%s"
\ No newline at end of file
+getCharts-by-name-and-version-url: "http://172.17.0.1:9100/helmrepo/api/charts/%s/%s"
+getXappHealth-url: "http://service-ricxqapp-%s-http.%s:8080/ric/v1/health/alive"
\ No newline at end of file
index c24500f..6c54b2b 100644 (file)
@@ -35,6 +35,7 @@ type Conf struct {
        GetChartsByNameAndVersionURL string `yaml:"getCharts-by-name-and-version-url"`
        DownloadChartURLFormat       string `yaml:"download-charts-url-format"`
        MockServer                   string `yaml:"mock-server"`
+       GETxAPPHealthURL             string `yaml:"getXappHealth-url"`
 }
 
 func ReadConfiguration(configFile string) (c *Conf, err error) {
index d007da4..3046559 100644 (file)
 
 package health
 
-import "gerrit.o-ran-sc.org/r/ric-plt/ricdms/pkg/models"
+import (
+       "fmt"
+       "net/http"
+
+       "gerrit.o-ran-sc.org/r/ric-plt/ricdms/pkg/models"
+       "gerrit.o-ran-sc.org/r/ric-plt/ricdms/pkg/ricdms"
+)
 
 var (
        HEALTHY = "Service is running healthy"
@@ -28,6 +34,7 @@ var (
 
 type IHealthChecker interface {
        GetStatus() *models.Status
+       GetxAppStatus(appName, namespace string) *models.Status
 }
 
 type HealthChecker struct {
@@ -41,3 +48,20 @@ func (h *HealthChecker) GetStatus() *models.Status {
                Status: &HEALTHY,
        }
 }
+
+func (h *HealthChecker) GetxAppStatus(appName, namespace string) *models.Status {
+       resp, err := http.Get(fmt.Sprintf(ricdms.Config.GETxAPPHealthURL, appName, namespace))
+       if err != nil {
+               ricdms.Logger.Error("Received error while fetching health info: %v", err)
+               return nil
+       }
+
+       if resp.StatusCode != http.StatusOK {
+               ricdms.Logger.Error("xApp is not healthy (http status=%s)", resp.Status)
+               return nil
+       }
+
+       return &models.Status{
+               Status: &HEALTHY,
+       }
+}
index 46a4387..b17c7ad 100644 (file)
@@ -70,6 +70,12 @@ func (r *Restful) setupHandler() {
                return resp
        })
 
+       api.HealthGetHealthcheckXAppXAppNameNamespaceNamespaceHandler = health.GetHealthcheckXAppXAppNameNamespaceNamespaceHandlerFunc(func(param health.GetHealthcheckXAppXAppNameNamespaceNamespaceParams) middleware.Responder {
+               ricdms.Logger.Debug("==> Healthcheck for xApp is invoked")
+               resp := r.rh.GetxAppHealth(param.XAppName, param.Namespace)
+               return resp
+       })
+
        api.OnboardPostOnboardxAppsHandler = onboard.PostOnboardxAppsHandlerFunc(func(poap onboard.PostOnboardxAppsParams) middleware.Responder {
                ricdms.Logger.Debug("==> onboard API invoked.")
                resp := r.rh.OnBoard(poap.Body)
index 7cc8efe..e0d7df2 100644 (file)
@@ -47,6 +47,15 @@ func (rh *Resthook) GetDMSHealth() (resp middleware.Responder) {
        return health.NewGetHealthCheckOK().WithPayload(rh.HealthChecker.GetStatus())
 }
 
+func (rh *Resthook) GetxAppHealth(appname, namespace string) (resp middleware.Responder) {
+       ricdms.Logger.Debug("Healthchecker: xApp health check is initiated")
+       status := rh.HealthChecker.GetxAppStatus(appname, namespace)
+       if status == nil {
+               return health.NewGetHealthCheckInternalServerError()
+       }
+       return health.NewGetHealthCheckOK().WithPayload(status)
+}
+
 func (rh *Resthook) OnBoard(params *models.Descriptor) (resp middleware.Responder) {
        ricdms.Logger.Debug("onboarder: invoked")
        return rh.Onboarder.Onboard(params)
index 7b65f15..40b32ac 100644 (file)
@@ -42,7 +42,6 @@ import (
        h "gerrit.o-ran-sc.org/r/ric-plt/ricdms/pkg/restapi/operations/health"
        "gerrit.o-ran-sc.org/r/ric-plt/ricdms/pkg/ricdms"
        "github.com/stretchr/testify/assert"
-       "github.com/stretchr/testify/mock"
 )
 
 var rh *Resthook
@@ -55,7 +54,7 @@ func TestMain(m *testing.M) {
        }
        ricdms.Init()
        rh = &Resthook{
-               HealthChecker: HealthCheckerMock{},
+               HealthChecker: health.NewHealthChecker(),
                Onboarder:     onboard.NewOnboarder(),
                ChartMgr:      ch.NewChartmgr(),
                DeployMgr:     deploy.NewDeploymentManager(),
@@ -78,6 +77,54 @@ func TestHealth(t *testing.T) {
        }
 }
 
+func TestHealthxAppFail(t *testing.T) {
+       svr := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               w.WriteHeader(501)
+       }))
+
+       svr.Listener.Close()
+       svr.Listener, _ = net.Listen("tcp", ricdms.Config.MockServer)
+
+       svr.Start()
+       defer svr.Close()
+
+       resp := rh.GetxAppHealth("test", "test")
+       switch resp.(type) {
+       case *h.GetHealthCheckOK:
+               assert.Fail(t, "Health check should not be okay: %v", resp)
+
+       case *h.GetHealthCheckInternalServerError:
+               break
+
+       default:
+               assert.Fail(t, "Unknown type of resp : %v", resp)
+       }
+}
+
+func TestHealthxApp(t *testing.T) {
+       svr := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               w.WriteHeader(http.StatusOK)
+       }))
+
+       svr.Listener.Close()
+       svr.Listener, _ = net.Listen("tcp", ricdms.Config.MockServer)
+
+       svr.Start()
+       defer svr.Close()
+
+       resp := rh.GetxAppHealth("test", "test")
+       switch resp.(type) {
+       case *h.GetHealthCheckOK:
+               assert.Equal(t, successStatus, resp.(*h.GetHealthCheckOK).Payload)
+
+       case *h.GetHealthCheckInternalServerError:
+               assert.Fail(t, "Internal Server generated: %v", resp)
+
+       default:
+               assert.Fail(t, "Unknown type of resp : %v", resp)
+       }
+}
+
 func TestOnboard(t *testing.T) {
        xApp := &models.Descriptor{
                Config: "SAMPLE_CONFIGURATION",
@@ -219,11 +266,3 @@ func TestUninstallxApp(t *testing.T) {
                assert.Fail(t, "response type did not match actual: %T", response)
        }
 }
-
-type HealthCheckerMock struct {
-       mock.Mock
-}
-
-func (h HealthCheckerMock) GetStatus() *models.Status {
-       return successStatus
-}