github.com/kserve/kserve v0.7.0
github.com/pkg/errors v0.9.1 // indirect
github.com/stretchr/testify v1.8.1
+ gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
+ k8s.io/api v0.20.2
+ k8s.io/apimachinery v0.20.2
k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible
)
require (
github.com/spf13/viper v1.7.0
github.com/xeipuuv/gojsonschema v1.2.0
- gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0
)
require (
gopkg.in/ini.v1 v1.56.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- k8s.io/api v0.20.2 // indirect
k8s.io/apiextensions-apiserver v0.20.2 // indirect
- k8s.io/apimachinery v0.20.2 // indirect
k8s.io/klog v1.0.0 // indirect
k8s.io/klog/v2 v2.4.0 // indirect
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 // indirect
return
}
- err := ipsAdapter.Deploy(name, version)
+ _, err := ipsAdapter.Deploy(name, version)
if err != nil {
utils.WriteError(c.Writer, err)
return
"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/commons/types"
)
const (
type Command interface {
Init(kubeconfigPath string) error
+ Create(values types.Values) (string, error)
}
type Client struct {
}
return
}
+
+func (c *Client) Create(values types.Values) (revision string, err error) {
+ logger.Logging(logger.DEBUG, "IN")
+ defer logger.Logging(logger.DEBUG, "OUT")
+
+ info := convertValuesToInferenceService(values)
+ if err != nil {
+ return
+ }
+
+ _, err = c.api.Create(&info)
+ if err != nil {
+ logger.Logging(logger.ERROR, err.Error())
+ err = errors.InternalServerError{Message: err.Error()}
+ return
+ }
+ return
+}
--- /dev/null
+/*
+==================================================================================
+
+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 kserve
+
+import (
+ "strconv"
+
+ api_v1beta1 "github.com/kserve/kserve/pkg/apis/serving/v1beta1"
+ core_v1 "k8s.io/api/core/v1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "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/commons/types"
+)
+
+func convertValuesToInferenceService(values types.Values) (ifsv api_v1beta1.InferenceService) {
+ logger.Logging(logger.DEBUG, "IN")
+ defer logger.Logging(logger.DEBUG, "OUT")
+
+ maxReplicas, err := strconv.Atoi(values.MAXReplicas)
+ if err != nil {
+ logger.Logging(logger.ERROR, err.Error())
+ maxReplicas = 1
+ }
+
+ minReplicas, err := strconv.Atoi(values.MINReplicas)
+ if err != nil {
+ logger.Logging(logger.ERROR, err.Error())
+ minReplicas = 1
+ }
+
+ ifsv = api_v1beta1.InferenceService{
+ TypeMeta: v1.TypeMeta{
+ Kind: "InferenceService",
+ APIVersion: "serving.kserve.io/v1beta1",
+ },
+ ObjectMeta: v1.ObjectMeta{
+ Name: values.FullName,
+ Namespace: ips_namespace,
+ Labels: map[string]string{
+ "controller-tools.k8s.io": "1.0",
+ "app": values.FullName,
+ },
+ },
+ Spec: api_v1beta1.InferenceServiceSpec{
+ Predictor: api_v1beta1.PredictorSpec{
+ ComponentExtensionSpec: api_v1beta1.ComponentExtensionSpec{
+ MaxReplicas: maxReplicas,
+ MinReplicas: &minReplicas,
+ },
+ PodSpec: api_v1beta1.PodSpec{
+ ServiceAccountName: values.RICServiceAccountName,
+ },
+ },
+ },
+ Status: api_v1beta1.InferenceServiceStatus{},
+ }
+
+ switch values.Engine {
+ case "tensorflow":
+ ifsv.Spec.Predictor.Tensorflow = &api_v1beta1.TFServingSpec{
+ PredictorExtensionSpec: api_v1beta1.PredictorExtensionSpec{
+ StorageURI: &values.StorageURI,
+ Container: core_v1.Container{
+ Image: values.Image,
+ Ports: []core_v1.ContainerPort{
+ {
+ Name: "h2c",
+ ContainerPort: 9000,
+ Protocol: "TCP",
+ },
+ },
+ },
+ },
+ }
+ case "sklearn":
+ ifsv.Spec.Predictor.SKLearn = &api_v1beta1.SKLearnSpec{
+ PredictorExtensionSpec: api_v1beta1.PredictorExtensionSpec{
+ StorageURI: &values.StorageURI,
+ Container: core_v1.Container{
+ Image: values.Image,
+ Ports: []core_v1.ContainerPort{
+ {
+ Name: "h2c",
+ ContainerPort: 9000,
+ Protocol: "TCP",
+ },
+ },
+ },
+ },
+ }
+ }
+
+ if values.CanaryTrafficPercent >= 0 {
+ ifsv.Spec.Predictor.CanaryTrafficPercent = &values.CanaryTrafficPercent
+ }
+
+ if values.ResourceVersion != "" {
+ ifsv.ResourceVersion = values.ResourceVersion
+ }
+
+ return
+}
--- /dev/null
+/*
+==================================================================================
+
+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 types
+
+type Values struct {
+ APIVersion string `yaml:"api_version"`
+ Engine string `yaml:"engine"`
+ Name string `yaml:"name"`
+ FullName string `yaml:"fullname"`
+ ImagePullPolicy string `yaml:"image_pull_policy"`
+ MAXReplicas string `yaml:"max_replicas"`
+ MINReplicas string `yaml:"min_replicas"`
+ Resources string `yaml:"resources"`
+ RICServiceAccountName string `yaml:"ric_serviceaccount_name"`
+ StorageURI string `yaml:"storageUri"`
+ Image string `yaml:"image"`
+ ResourceVersion string
+ CanaryTrafficPercent int64
+}
)
type Command interface {
- Deploy(name string, version string) error
+ Deploy(name string, version string) (string, error)
}
type Executor struct {
var kserveClient kserve.Command
var onboardClient onboard.Command
+var removeFunc func(string) error
+
func init() {
kserveClient = &kserve.Client{}
- onboardClient = onboard.Executor{}
kubeconfigPath := os.Getenv("KUBECONFIG")
err := kserveClient.Init(kubeconfigPath)
if err != nil {
os.Exit(8)
}
+
+ onboardClient = onboard.Executor{}
+
+ removeFunc = func(path string) (err error) {
+ err = os.RemoveAll(path)
+ return
+ }
}
-func (Executor) Deploy(name string, version string) error {
+func (Executor) Deploy(name string, version string) (revision string, err error) {
logger.Logging(logger.DEBUG, "IN")
defer logger.Logging(logger.DEBUG, "OUT")
- // TODO: Get object from onboard & Deploy using kserveClient
+ path, err := onboardClient.Download(name, version)
+ if err != nil {
+ return
+ }
+ defer removeFunc(path)
+
+ values, err := valueParse(path)
+ if err != nil {
+ logger.Logging(logger.ERROR, err.Error())
+ return
+ }
- return nil
+ revision, err = kserveClient.Create(values)
+ if err != nil {
+ return
+ }
+ return
}
--- /dev/null
+/*
+==================================================================================
+
+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 adapter
+
+import (
+ "os"
+ "path/filepath"
+
+ "gopkg.in/yaml.v1"
+
+ "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/commons/types"
+)
+
+func valueParse(path string) (values types.Values, err error) {
+ logger.Logging(logger.DEBUG, "IN")
+ defer logger.Logging(logger.DEBUG, "OUT")
+
+ filePath, err := getValuesFilePath(path)
+ if err != nil {
+ return
+ }
+
+ b, err := os.ReadFile(filePath)
+ if err != nil {
+ logger.Logging(logger.ERROR, err.Error())
+ err = errors.IOError{Message: err.Error()}
+ return
+ }
+
+ err = yaml.Unmarshal(b, &values)
+ if err != nil {
+ logger.Logging(logger.ERROR, err.Error())
+ err = errors.IOError{Message: err.Error()}
+ return
+ }
+ values.CanaryTrafficPercent = -1
+
+ return
+}
+
+func getValuesFilePath(root string) (path string, err error) {
+ logger.Logging(logger.DEBUG, "IN")
+ defer logger.Logging(logger.DEBUG, "OUT")
+
+ files, err := os.ReadDir(root)
+ if err != nil {
+ logger.Logging(logger.ERROR, err.Error())
+ return "", errors.IOError{Message: err.Error()}
+ }
+
+ for _, file := range files {
+ if file.IsDir() {
+ path = filepath.Join(root, file.Name())
+ }
+ }
+ path = filepath.Join(path, "values.yaml")
+ return
+}