Implementation of info feature 10/11210/2
authorYouhwan Seol <yh.seol@samsung.com>
Wed, 22 Feb 2023 06:04:49 +0000 (15:04 +0900)
committerYouhwan Seol <yh.seol@samsung.com>
Thu, 25 May 2023 01:14:27 +0000 (10:14 +0900)
Change-Id: Idf51c10db73451b09593db84c84ea37e84ac2817
Signed-off-by: Youhwan Seol <yh.seol@samsung.com>
pkg/api/rest_server.go
pkg/api/v1/info/info.go [new file with mode: 0644]
pkg/client/kserve/client.go
pkg/client/kserve/utils.go
pkg/commons/types/values.go
pkg/controller/v1/adapter/controller.go

index f4e28e6..3d9db75 100644 (file)
@@ -25,6 +25,7 @@ import (
        "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/api/commons/url"
        "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/api/v1/deployment"
        "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/api/v1/healthcheck"
+       "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/api/v1/info"
        "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/api/v1/revision"
        "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/api/v1/status"
        "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/commons/logger"
@@ -33,15 +34,17 @@ import (
 var (
        deploymentExecutor  deployment.Command
        healthcheckExecutor healthcheck.Command
-       reivisonExecutor    revision.Command
+       revisionExecutor    revision.Command
        statusExecutor      status.Command
+       infoExecutor        info.Command
 )
 
 func init() {
        deploymentExecutor = deployment.Executor{}
        healthcheckExecutor = healthcheck.Executor{}
-       reivisonExecutor = revision.Executor{}
+       revisionExecutor = revision.Executor{}
        statusExecutor = status.Executor{}
+       infoExecutor = info.Executor{}
 }
 
 func setupRouter() (router *gin.Engine) {
@@ -63,7 +66,7 @@ func setupRouter() (router *gin.Engine) {
 
                revision := v1.Group(url.IPS() + url.Revision())
                {
-                       revision.GET("", reivisonExecutor.Get)
+                       revision.GET("", revisionExecutor.Get)
                }
 
                status := v1.Group(url.IPS() + url.Status())
@@ -72,7 +75,9 @@ func setupRouter() (router *gin.Engine) {
                }
 
                info := v1.Group(url.IPS() + url.Info())
-               // info.GET()
+               {
+                       info.GET("", infoExecutor.Get)
+               }
 
                _, _, _, _ = healthcheck, revision, status, info
        }
diff --git a/pkg/api/v1/info/info.go b/pkg/api/v1/info/info.go
new file mode 100644 (file)
index 0000000..44011f4
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+==================================================================================
+
+Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved.
+
+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.
+==================================================================================
+*/
+
+package info
+
+import (
+       "encoding/json"
+       "net/http"
+
+       "github.com/gin-gonic/gin"
+
+       "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/api/commons/utils"
+       "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/commons/errors"
+       "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/commons/logger"
+       "gerrit.o-ran-sc.org/r/aiml-fw/aihp/ips/kserve-adapter/pkg/controller/v1/adapter"
+)
+
+type Command interface {
+       Get(c *gin.Context)
+}
+
+type Executor struct {
+       Command
+}
+
+var ipsAdapter adapter.Command
+
+func init() {
+       ipsAdapter = adapter.Executor{}
+}
+
+func (Executor) Get(c *gin.Context) {
+       logger.Logging(logger.DEBUG, "IN")
+       defer logger.Logging(logger.DEBUG, "OUT")
+
+       name := c.Query("name")
+
+       infoList, err := ipsAdapter.Info(name)
+       if err != nil {
+               utils.WriteError(c.Writer, errors.InternalServerError{Message: err.Error()})
+               return
+       }
+
+       data, err := json.Marshal(infoList)
+       if err != nil {
+               utils.WriteError(c.Writer, err)
+               return
+       }
+
+       utils.WriteSuccess(c.Writer, http.StatusAccepted, data)
+}
index 989cf05..c282bac 100644 (file)
@@ -46,6 +46,7 @@ type Command interface {
        Update(values types.Values) (string, error)
        Revision(name string) (revisionList types.Revision, err error)
        Status(name string) (statusList types.Status, err error)
+       Info(name string) (infoList types.Info, err error)
 }
 
 type Client struct {
@@ -235,3 +236,46 @@ func (c *Client) Status(name string) (statusList types.Status, err error) {
 
        return
 }
+
+func (c *Client) Info(name string) (infoList types.Info, err error) {
+       logger.Logging(logger.DEBUG, "IN")
+       defer logger.Logging(logger.DEBUG, "OUT")
+
+       infoList.Info = make(map[string]types.InfoItem)
+
+       if name == "" {
+               ifsvList, e := c.api.List(v1.ListOptions{})
+               if e != nil {
+                       logger.Logging(logger.ERROR, e.Error())
+                       err = errors.InternalServerError{
+                               Message: e.Error(),
+                       }
+                       return
+               }
+
+               for _, ifsv := range ifsvList.Items {
+                       info, e := makeInfo(ifsv)
+                       if e != nil {
+                               err = e
+                               return
+                       }
+                       infoList.Info[ifsv.Name] = info
+               }
+
+       } else {
+               ifsv, e := c.Get(name)
+               if e != nil {
+                       err = e
+                       return
+               }
+
+               info, e := makeInfo(*ifsv)
+               if e != nil {
+                       err = e
+                       return
+               }
+               infoList.Info[ifsv.Name] = info
+       }
+
+       return
+}
index 4e32ec5..b597ba8 100644 (file)
@@ -162,3 +162,34 @@ func makeStatus(ifsv api_v1beta1.InferenceService) (status []types.StatusItem, e
        }
        return
 }
+
+func makeInfo(ifsv api_v1beta1.InferenceService) (info types.InfoItem, err error) {
+       logger.Logging(logger.DEBUG, "IN")
+       defer logger.Logging(logger.DEBUG, "OUT")
+
+       var resources []byte
+
+       switch {
+       case ifsv.Spec.Predictor.Tensorflow != nil:
+               resources, _ = json.Marshal(ifsv.Spec.Predictor.Tensorflow.Resources)
+       case ifsv.Spec.Predictor.SKLearn != nil:
+               resources, _ = json.Marshal(ifsv.Spec.Predictor.SKLearn.Resources)
+       default:
+               err = errors.InternalServerError{Message: "PredictorSpec does not have information."}
+               return
+       }
+
+       json.Unmarshal(resources, &info.Resources)
+
+       for _, traffic := range ifsv.Status.Components["predictor"].Traffic {
+               info.Traffic = append(info.Traffic, types.Traffic{
+                       Tag:            traffic.Tag,
+                       RevisionName:   traffic.RevisionName,
+                       LatestRevision: strconv.FormatBool(*traffic.LatestRevision),
+                       Percent:        strconv.FormatInt(*traffic.Percent, 10),
+                       URL:            traffic.URL.String(),
+               })
+       }
+
+       return
+}
index 3e4a501..f27a5ad 100644 (file)
@@ -51,6 +51,33 @@ type StatusItem struct {
        Message            string `json:"message,omitempty" example:"{message}" format:"string"`
 }
 
+type Traffic struct {
+       Tag            string `json:"tag,omitempty" example:"prev" format:"string"`
+       RevisionName   string `json:"revisionName" example:"{revision}" format:"string"`
+       LatestRevision string `json:"latestRevision,omitempty" example:"{True / False}" format:"string"`
+       Percent        string `json:"percent,omitempty" example:"90" format:"string"`
+       URL            string `json:"url,omitempty" example:"url" format:"string"`
+}
+
+type Resources struct {
+       Limits   Limits   `json:"limits"`
+       Requests Requests `json:"requests"`
+}
+
+type Limits struct {
+       CPU    string `json:"cpu" example:"{1}" format:"string"`
+       Memory string `json:"memory" example:"{2Gi}" format:"string"`
+}
+
+type Requests struct {
+       CPU    string `json:"cpu" example:"{1}" format:"string"`
+       Memory string `json:"memory" example:"{2Gi}" format:"string"`
+}
+
+type InfoItem struct {
+       Traffic   []Traffic `json:"traffic"`
+       Resources Resources `json:"resources"`
+}
 type Revision struct {
        Revision map[string]RevisionItem `json:"revision"`
 }
@@ -58,3 +85,7 @@ type Revision struct {
 type Status struct {
        Status map[string][]StatusItem `json:"status"`
 }
+
+type Info struct {
+       Info map[string]InfoItem `json:"info"`
+}
index f88524d..e4826c8 100644 (file)
@@ -36,6 +36,7 @@ type Command interface {
        Update(name string, version string, canaryTrafficRatio string) (string, error)
        Revision(name string) (revisionList types.Revision, err error)
        Status(name string) (types.Status, error)
+       Info(name string) (types.Info, error)
 }
 
 type Executor struct {
@@ -152,3 +153,11 @@ func (Executor) Status(name string) (result types.Status, err error) {
        result, err = kserveClient.Status(name)
        return
 }
+
+func (Executor) Info(name string) (result types.Info, err error) {
+       logger.Logging(logger.DEBUG, "IN")
+       defer logger.Logging(logger.DEBUG, "OUT")
+
+       result, err = kserveClient.Info(name)
+       return
+}