diff --git a/config/default/configmap/kfservice.yaml b/config/default/configmap/kfservice.yaml
index c2e258934b3..f6aa6e06fc6 100644
--- a/config/default/configmap/kfservice.yaml
+++ b/config/default/configmap/kfservice.yaml
@@ -4,7 +4,7 @@ metadata:
name: kfservice-config
namespace: kfserving-system
data:
- frameworks: |-
+ predictors: |-
{
"tensorflow": {
"image": "tensorflow/serving"
diff --git a/docs/apis/README.md b/docs/apis/README.md
index d55882f364e..3c0ea6ec741 100644
--- a/docs/apis/README.md
+++ b/docs/apis/README.md
@@ -479,11 +479,11 @@ ExplainerConfig
-
FrameworkConfig
+PredictorConfig
(Appears on:
-FrameworksConfig)
+PredictorsConfig)
@@ -507,11 +507,11 @@ string
-FrameworkHandler
+Predictor
-FrameworksConfig
+PredictorsConfig
@@ -527,8 +527,8 @@ string
tensorflow
-
-FrameworkConfig
+
+PredictorConfig
|
@@ -539,8 +539,8 @@ FrameworkConfig
tensorrt
-
-FrameworkConfig
+
+PredictorConfig
|
@@ -551,8 +551,8 @@ FrameworkConfig
xgboost
-
-FrameworkConfig
+
+PredictorConfig
|
@@ -563,8 +563,8 @@ FrameworkConfig
sklearn
-
-FrameworkConfig
+
+PredictorConfig
|
@@ -575,8 +575,8 @@ FrameworkConfig
pytorch
-
-FrameworkConfig
+
+PredictorConfig
|
@@ -587,8 +587,8 @@ FrameworkConfig
onnx
-
-FrameworkConfig
+
+PredictorConfig
|
diff --git a/pkg/apis/serving/v1alpha2/explainer.go b/pkg/apis/serving/v1alpha2/explainer.go
index 99391fdff1b..2b0d4416615 100644
--- a/pkg/apis/serving/v1alpha2/explainer.go
+++ b/pkg/apis/serving/v1alpha2/explainer.go
@@ -15,22 +15,21 @@ package v1alpha2
import (
"fmt"
+
v1 "k8s.io/api/core/v1"
"k8s.io/klog"
)
-type ExplainerHandler interface {
+type Explainer interface {
GetStorageUri() string
- CreateExplainerServingContainer(modelName string, predictorHost string, config *ExplainersConfig) *v1.Container
+ CreateExplainerContainer(modelName string, predictorHost string, config *ExplainersConfig) *v1.Container
ApplyDefaults()
Validate() error
}
const (
- // ExactlyOneModelSpecViolatedError is a known error message
- ExactlyOneExplainerSpecViolatedError = "Exactly one of [Custom, Alibi] must be specified in ExplainerSpec"
- // AtLeastOneModelSpecViolatedError is a known error message
- AtLeastOneExplainerSpecViolatedError = "At least one of [Custom, Alibi] must be specified in ExplainerSpec"
+ // ExactlyOneExplainerViolatedError is a known error message
+ ExactlyOneExplainerViolatedError = "Exactly one of [Custom, Alibi] must be specified in ExplainerSpec"
)
// Returns a URI to the explainer. This URI is passed to the model-initializer via the ModelInitializerSourceUriInternalAnnotationKey
@@ -38,8 +37,8 @@ func (m *ExplainerSpec) GetStorageUri() string {
return getExplainerHandler(m).GetStorageUri()
}
-func (m *ExplainerSpec) CreateExplainerServingContainer(modelName string, predictorHost string, config *ExplainersConfig) *v1.Container {
- return getExplainerHandler(m).CreateExplainerServingContainer(modelName, predictorHost, config)
+func (m *ExplainerSpec) CreateExplainerContainer(modelName string, predictorHost string, config *ExplainersConfig) *v1.Container {
+ return getExplainerHandler(m).CreateExplainerContainer(modelName, predictorHost, config)
}
func (m *ExplainerSpec) ApplyDefaults() {
@@ -47,11 +46,11 @@ func (m *ExplainerSpec) ApplyDefaults() {
}
func (m *ExplainerSpec) Validate() error {
- handler, err := makeExplainerHandler(m)
+ explainer, err := makeExplainer(m)
if err != nil {
return err
}
- return handler.Validate()
+ return explainer.Validate()
}
type ExplainerConfig struct {
@@ -63,29 +62,25 @@ type ExplainersConfig struct {
AlibiExplainer ExplainerConfig `json:"alibi,omitempty"`
}
-func getExplainerHandler(modelSpec *ExplainerSpec) ExplainerHandler {
- handler, err := makeExplainerHandler(modelSpec)
+func getExplainerHandler(modelSpec *ExplainerSpec) Explainer {
+ explainer, err := makeExplainer(modelSpec)
if err != nil {
klog.Fatal(err)
}
- return handler
+ return explainer
}
-func makeExplainerHandler(explainerSpec *ExplainerSpec) (ExplainerHandler, error) {
- handlers := []ExplainerHandler{}
+func makeExplainer(explainerSpec *ExplainerSpec) (Explainer, error) {
+ handlers := []Explainer{}
if explainerSpec.Custom != nil {
handlers = append(handlers, explainerSpec.Custom)
}
if explainerSpec.Alibi != nil {
handlers = append(handlers, explainerSpec.Alibi)
}
-
- if len(handlers) == 0 {
- return nil, fmt.Errorf(AtLeastOneExplainerSpecViolatedError)
- }
if len(handlers) != 1 {
- return nil, fmt.Errorf(ExactlyOneExplainerSpecViolatedError)
+ return nil, fmt.Errorf(ExactlyOneExplainerViolatedError)
}
return handlers[0], nil
}
diff --git a/pkg/apis/serving/v1alpha2/explainer_alibi.go b/pkg/apis/serving/v1alpha2/explainer_alibi.go
index 0aa1e9790cf..08993742a8b 100644
--- a/pkg/apis/serving/v1alpha2/explainer_alibi.go
+++ b/pkg/apis/serving/v1alpha2/explainer_alibi.go
@@ -2,10 +2,11 @@ package v1alpha2
import (
"fmt"
+ "strings"
+
"github.com/kubeflow/kfserving/pkg/constants"
"github.com/kubeflow/kfserving/pkg/utils"
v1 "k8s.io/api/core/v1"
- "strings"
)
var (
@@ -21,15 +22,15 @@ func (s *AlibiExplainerSpec) GetStorageUri() string {
return s.StorageURI
}
-func (s *AlibiExplainerSpec) CreateExplainerServingContainer(modelName string, predictorHost string, config *ExplainersConfig) *v1.Container {
+func (s *AlibiExplainerSpec) CreateExplainerContainer(modelName string, predictorHost string, config *ExplainersConfig) *v1.Container {
imageName := AlibiImageName
if config.AlibiExplainer.ContainerImage != "" {
imageName = config.AlibiExplainer.ContainerImage
}
var args = []string{
- constants.ModelServerArgsModelName, modelName,
- constants.ModelServerArgsPredictorHost, predictorHost,
+ constants.ArgumentModelName, modelName,
+ constants.ArgumentPredictorHost, predictorHost,
}
if s.StorageURI != "" {
diff --git a/pkg/apis/serving/v1alpha2/framework.go b/pkg/apis/serving/v1alpha2/framework.go
deleted file mode 100644
index d97f1aeae40..00000000000
--- a/pkg/apis/serving/v1alpha2/framework.go
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
-Copyright 2019 kubeflow.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.
-*/
-
-package v1alpha2
-
-import (
- "fmt"
-
- "github.com/kubeflow/kfserving/pkg/constants"
- v1 "k8s.io/api/core/v1"
- resource "k8s.io/apimachinery/pkg/api/resource"
- "k8s.io/klog"
-)
-
-type FrameworkHandler interface {
- GetStorageUri() string
- CreateModelServingContainer(modelName string, config *FrameworksConfig) *v1.Container
- ApplyDefaults()
- Validate() error
-}
-
-const (
- // ExactlyOneModelSpecViolatedError is a known error message
- ExactlyOneModelSpecViolatedError = "Exactly one of [Custom, ONNX, Tensorflow, TensorRT, SKLearn, XGBoost] must be specified in ModelSpec"
- // AtLeastOneModelSpecViolatedError is a known error message
- AtLeastOneModelSpecViolatedError = "At least one of [Custom, ONNX, Tensorflow, TensorRT, SKLearn, XGBoost] must be specified in ModelSpec"
-)
-
-var (
- DefaultMemory = resource.MustParse("2Gi")
- DefaultCPU = resource.MustParse("1")
-)
-
-// Returns a URI to the model. This URI is passed to the storage-initializer via the StorageInitializerSourceUriInternalAnnotationKey
-func (m *PredictorSpec) GetStorageUri() string {
- return getHandler(m).GetStorageUri()
-}
-
-func (m *PredictorSpec) CreateModelServingContainer(modelName string, config *FrameworksConfig) *v1.Container {
- return getHandler(m).CreateModelServingContainer(modelName, config)
-}
-
-func (m *PredictorSpec) ApplyDefaults() {
- getHandler(m).ApplyDefaults()
-}
-
-func (m *PredictorSpec) Validate() error {
- handler, err := makeHandler(m)
- if err != nil {
- return err
- }
- return handler.Validate()
-}
-
-type FrameworkConfig struct {
- ContainerImage string `json:"image"`
-
- //TODO add readiness/liveness probe config
-}
-type FrameworksConfig struct {
- Tensorflow FrameworkConfig `json:"tensorflow,omitempty"`
- TensorRT FrameworkConfig `json:"tensorrt,omitempty"`
- Xgboost FrameworkConfig `json:"xgboost,omitempty"`
- SKlearn FrameworkConfig `json:"sklearn,omitempty"`
- PyTorch FrameworkConfig `json:"pytorch,omitempty"`
- ONNX FrameworkConfig `json:"onnx,omitempty"`
-}
-
-func setResourceRequirementDefaults(requirements *v1.ResourceRequirements) {
- if requirements.Requests == nil {
- requirements.Requests = v1.ResourceList{}
- }
-
- if _, ok := requirements.Requests[v1.ResourceCPU]; !ok {
- requirements.Requests[v1.ResourceCPU] = DefaultCPU
- }
- if _, ok := requirements.Requests[v1.ResourceMemory]; !ok {
- requirements.Requests[v1.ResourceMemory] = DefaultMemory
- }
-
- if requirements.Limits == nil {
- requirements.Limits = v1.ResourceList{}
- }
-
- if _, ok := requirements.Limits[v1.ResourceCPU]; !ok {
- requirements.Limits[v1.ResourceCPU] = DefaultCPU
- }
- if _, ok := requirements.Limits[v1.ResourceMemory]; !ok {
- requirements.Limits[v1.ResourceMemory] = DefaultMemory
- }
-}
-
-func isGPUEnabled(requirements v1.ResourceRequirements) bool {
- _, ok := requirements.Limits[constants.NvidiaGPUResourceType]
- return ok
-}
-
-func getHandler(modelSpec *PredictorSpec) FrameworkHandler {
- handler, err := makeHandler(modelSpec)
- if err != nil {
- klog.Fatal(err)
- }
-
- return handler
-}
-
-func makeHandler(predictorSpec *PredictorSpec) (FrameworkHandler, error) {
- handlers := []FrameworkHandler{}
- if predictorSpec.Custom != nil {
- handlers = append(handlers, predictorSpec.Custom)
- }
- if predictorSpec.XGBoost != nil {
- handlers = append(handlers, predictorSpec.XGBoost)
- }
- if predictorSpec.SKLearn != nil {
- handlers = append(handlers, predictorSpec.SKLearn)
- }
- if predictorSpec.Tensorflow != nil {
- handlers = append(handlers, predictorSpec.Tensorflow)
- }
- if predictorSpec.ONNX != nil {
- handlers = append(handlers, predictorSpec.ONNX)
- }
- if predictorSpec.PyTorch != nil {
- handlers = append(handlers, predictorSpec.PyTorch)
- }
- if predictorSpec.TensorRT != nil {
- handlers = append(handlers, predictorSpec.TensorRT)
- }
- if len(handlers) == 0 {
- return nil, fmt.Errorf(AtLeastOneModelSpecViolatedError)
- }
- if len(handlers) != 1 {
- return nil, fmt.Errorf(ExactlyOneModelSpecViolatedError)
- }
- return handlers[0], nil
-}
diff --git a/pkg/apis/serving/v1alpha2/framework_custom.go b/pkg/apis/serving/v1alpha2/framework_custom.go
index a1b4eedc423..8f2ddcf5ac9 100644
--- a/pkg/apis/serving/v1alpha2/framework_custom.go
+++ b/pkg/apis/serving/v1alpha2/framework_custom.go
@@ -32,10 +32,10 @@ func (c *CustomSpec) GetStorageUri() string {
return ""
}
-func (c *CustomSpec) CreateModelServingContainer(modelName string, config *FrameworksConfig) *v1.Container {
+func (c *CustomSpec) GetContainer(modelName string, config *PredictorsConfig) *v1.Container {
return &c.Container
}
-func (c *CustomSpec) CreateExplainerServingContainer(modelName string, predictUrl string, config *ExplainersConfig) *v1.Container {
+func (c *CustomSpec) CreateExplainerContainer(modelName string, predictUrl string, config *ExplainersConfig) *v1.Container {
return &c.Container
}
diff --git a/pkg/apis/serving/v1alpha2/framework_onnx.go b/pkg/apis/serving/v1alpha2/framework_onnx.go
index 5660b4451db..e12dab43191 100644
--- a/pkg/apis/serving/v1alpha2/framework_onnx.go
+++ b/pkg/apis/serving/v1alpha2/framework_onnx.go
@@ -39,7 +39,7 @@ func (s *ONNXSpec) GetStorageUri() string {
return s.StorageURI
}
-func (s *ONNXSpec) CreateModelServingContainer(modelName string, config *FrameworksConfig) *v1.Container {
+func (s *ONNXSpec) GetContainer(modelName string, config *PredictorsConfig) *v1.Container {
imageName := ONNXServingImageName
if config.ONNX.ContainerImage != "" {
imageName = config.ONNX.ContainerImage
diff --git a/pkg/apis/serving/v1alpha2/framework_onnx_test.go b/pkg/apis/serving/v1alpha2/framework_onnx_test.go
index 1a6b13d3bb5..c111add7d94 100644
--- a/pkg/apis/serving/v1alpha2/framework_onnx_test.go
+++ b/pkg/apis/serving/v1alpha2/framework_onnx_test.go
@@ -44,8 +44,8 @@ var onnxSpec = ONNXSpec{
RuntimeVersion: "someAmazingVersion",
}
-var onnxConfig = FrameworksConfig{
- ONNX: FrameworkConfig{
+var onnxConfig = PredictorsConfig{
+ ONNX: PredictorConfig{
ContainerImage: "someOtherImage",
},
}
@@ -65,12 +65,12 @@ func TestCreateOnnxModelServingContainer(t *testing.T) {
}
// Test Create with config
- container := onnxSpec.CreateModelServingContainer("someName", &onnxConfig)
+ container := onnxSpec.GetContainer("someName", &onnxConfig)
g.Expect(container).To(gomega.Equal(expectedContainer))
// Test Create without config
expectedContainer.Image = "mcr.microsoft.com/onnxruntime/server:someAmazingVersion"
- emptyConfig := FrameworksConfig{ONNX: FrameworkConfig{}}
- container = onnxSpec.CreateModelServingContainer("someName", &emptyConfig)
+ emptyConfig := PredictorsConfig{ONNX: PredictorConfig{}}
+ container = onnxSpec.GetContainer("someName", &emptyConfig)
g.Expect(container).To(gomega.Equal(expectedContainer))
}
diff --git a/pkg/apis/serving/v1alpha2/framework_scikit.go b/pkg/apis/serving/v1alpha2/framework_scikit.go
index 1e91878de53..b8d0eee1653 100644
--- a/pkg/apis/serving/v1alpha2/framework_scikit.go
+++ b/pkg/apis/serving/v1alpha2/framework_scikit.go
@@ -33,13 +33,13 @@ var (
DefaultSKLearnRuntimeVersion = "latest"
)
-var _ FrameworkHandler = (*SKLearnSpec)(nil)
+var _ Predictor = (*SKLearnSpec)(nil)
func (s *SKLearnSpec) GetStorageUri() string {
return s.StorageURI
}
-func (s *SKLearnSpec) CreateModelServingContainer(modelName string, config *FrameworksConfig) *v1.Container {
+func (s *SKLearnSpec) GetContainer(modelName string, config *PredictorsConfig) *v1.Container {
imageName := SKLearnServerImageName
if config.SKlearn.ContainerImage != "" {
imageName = config.SKlearn.ContainerImage
diff --git a/pkg/apis/serving/v1alpha2/framework_tensorflow.go b/pkg/apis/serving/v1alpha2/framework_tensorflow.go
index 3860b561c12..cf639408903 100644
--- a/pkg/apis/serving/v1alpha2/framework_tensorflow.go
+++ b/pkg/apis/serving/v1alpha2/framework_tensorflow.go
@@ -49,7 +49,7 @@ func (t *TensorflowSpec) GetStorageUri() string {
return t.StorageURI
}
-func (t *TensorflowSpec) CreateModelServingContainer(modelName string, config *FrameworksConfig) *v1.Container {
+func (t *TensorflowSpec) GetContainer(modelName string, config *PredictorsConfig) *v1.Container {
imageName := TensorflowServingImageName
if config.Tensorflow.ContainerImage != "" {
imageName = config.Tensorflow.ContainerImage
diff --git a/pkg/apis/serving/v1alpha2/framework_xgboost.go b/pkg/apis/serving/v1alpha2/framework_xgboost.go
index 42c2aa7761a..49cb6a4a1f4 100644
--- a/pkg/apis/serving/v1alpha2/framework_xgboost.go
+++ b/pkg/apis/serving/v1alpha2/framework_xgboost.go
@@ -37,7 +37,7 @@ func (x *XGBoostSpec) GetStorageUri() string {
return x.StorageURI
}
-func (x *XGBoostSpec) CreateModelServingContainer(modelName string, config *FrameworksConfig) *v1.Container {
+func (x *XGBoostSpec) GetContainer(modelName string, config *PredictorsConfig) *v1.Container {
imageName := XGBoostServerImageName
if config.Xgboost.ContainerImage != "" {
imageName = config.Xgboost.ContainerImage
diff --git a/pkg/apis/serving/v1alpha2/kfservice_framework_pytorch.go b/pkg/apis/serving/v1alpha2/kfservice_framework_pytorch.go
index e7eb0173142..2dbc4f00122 100644
--- a/pkg/apis/serving/v1alpha2/kfservice_framework_pytorch.go
+++ b/pkg/apis/serving/v1alpha2/kfservice_framework_pytorch.go
@@ -34,13 +34,13 @@ var (
DefaultPyTorchModelClassName = "PyTorchModel"
)
-var _ FrameworkHandler = (*PyTorchSpec)(nil)
+var _ Predictor = (*PyTorchSpec)(nil)
func (s *PyTorchSpec) GetStorageUri() string {
return s.StorageURI
}
-func (s *PyTorchSpec) CreateModelServingContainer(modelName string, config *FrameworksConfig) *v1.Container {
+func (s *PyTorchSpec) GetContainer(modelName string, config *PredictorsConfig) *v1.Container {
imageName := PyTorchServerImageName
if config.PyTorch.ContainerImage != "" {
imageName = config.PyTorch.ContainerImage
diff --git a/pkg/apis/serving/v1alpha2/kfservice_framework_tensorrt.go b/pkg/apis/serving/v1alpha2/kfservice_framework_tensorrt.go
index b6a5443751d..ff114d799fb 100644
--- a/pkg/apis/serving/v1alpha2/kfservice_framework_tensorrt.go
+++ b/pkg/apis/serving/v1alpha2/kfservice_framework_tensorrt.go
@@ -38,7 +38,7 @@ func (t *TensorRTSpec) GetStorageUri() string {
return t.StorageURI
}
-func (t *TensorRTSpec) CreateModelServingContainer(modelName string, config *FrameworksConfig) *v1.Container {
+func (t *TensorRTSpec) GetContainer(modelName string, config *PredictorsConfig) *v1.Container {
imageName := DefaultTensorRTISImageName
if config.TensorRT.ContainerImage != "" {
imageName = config.TensorRT.ContainerImage
diff --git a/pkg/apis/serving/v1alpha2/kfservice_framework_tensorrt_test.go b/pkg/apis/serving/v1alpha2/kfservice_framework_tensorrt_test.go
index c27c3bf3252..f11cd504f69 100644
--- a/pkg/apis/serving/v1alpha2/kfservice_framework_tensorrt_test.go
+++ b/pkg/apis/serving/v1alpha2/kfservice_framework_tensorrt_test.go
@@ -39,8 +39,8 @@ func TestCreateModelServingContainer(t *testing.T) {
},
},
}
- var config = FrameworksConfig{
- TensorRT: FrameworkConfig{
+ var config = PredictorsConfig{
+ TensorRT: PredictorConfig{
ContainerImage: "someOtherImage",
},
}
@@ -71,12 +71,12 @@ func TestCreateModelServingContainer(t *testing.T) {
}
// Test Create without config
- container := spec.CreateModelServingContainer("someName", &config)
+ container := spec.GetContainer("someName", &config)
g.Expect(container).To(gomega.Equal(expectedContainer))
// Test Create with config
expectedContainer.Image = "nvcr.io/nvidia/tensorrtserver:19.05-py3"
- emptyConfig := FrameworksConfig{TensorRT: FrameworkConfig{}}
- container = spec.CreateModelServingContainer("someName", &emptyConfig)
+ emptyConfig := PredictorsConfig{TensorRT: PredictorConfig{}}
+ container = spec.GetContainer("someName", &emptyConfig)
g.Expect(container).To(gomega.Equal(expectedContainer))
}
diff --git a/pkg/apis/serving/v1alpha2/kfservice_validation.go b/pkg/apis/serving/v1alpha2/kfservice_validation.go
index 2c009c7ac0e..89b7c3ef4b4 100644
--- a/pkg/apis/serving/v1alpha2/kfservice_validation.go
+++ b/pkg/apis/serving/v1alpha2/kfservice_validation.go
@@ -18,8 +18,6 @@ package v1alpha2
import (
"fmt"
- "regexp"
- "strings"
runtime "k8s.io/apimachinery/pkg/runtime"
)
@@ -64,12 +62,13 @@ func validateKFService(kfsvc *KFService) error {
if kfsvc == nil {
return fmt.Errorf("Unable to validate, KFService is nil")
}
- if err := validateModelSpec(&kfsvc.Spec.Default.Predictor); err != nil {
- return err
+ endpoints := []*EndpointSpec{
+ &kfsvc.Spec.Default,
+ kfsvc.Spec.Canary,
}
- if kfsvc.Spec.Canary != nil {
- if err := validateModelSpec(&kfsvc.Spec.Canary.Predictor); err != nil {
+ for _, endpoint := range endpoints {
+ if err := validateEndpoint(endpoint); err != nil {
return err
}
}
@@ -80,56 +79,22 @@ func validateKFService(kfsvc *KFService) error {
return nil
}
-func validateModelSpec(spec *PredictorSpec) error {
- if spec == nil {
+func validateEndpoint(endpoint *EndpointSpec) error {
+ if endpoint == nil {
return nil
}
- if err := spec.Validate(); err != nil {
- return err
- }
- if err := validateStorageURI(spec.GetStorageUri()); err != nil {
+ if err := endpoint.Predictor.Validate(); err != nil {
return err
}
- if err := validateReplicas(spec.MinReplicas, spec.MaxReplicas); err != nil {
- return err
- }
- return nil
-}
-
-func validateStorageURI(storageURI string) error {
- if storageURI == "" {
- return nil
- }
-
- // local path (not some protocol?)
- if !regexp.MustCompile("\\w+?://").MatchString(storageURI) {
- return nil
- }
-
- // one of the prefixes we know?
- for _, prefix := range SupportedStorageURIPrefixList {
- if strings.HasPrefix(storageURI, prefix) {
- return nil
+ if endpoint.Transformer != nil {
+ if err := endpoint.Transformer.Validate(); err != nil {
+ return err
}
}
-
- azureURIMatcher := regexp.MustCompile(AzureBlobURIRegEx)
- if parts := azureURIMatcher.FindStringSubmatch(storageURI); parts != nil {
- return nil
- }
-
- return fmt.Errorf(UnsupportedStorageURIFormatError, strings.Join(SupportedStorageURIPrefixList, ", "), storageURI)
-}
-
-func validateReplicas(minReplicas int, maxReplicas int) error {
- if minReplicas < 0 {
- return fmt.Errorf(MinReplicasLowerBoundExceededError)
- }
- if maxReplicas < 0 {
- return fmt.Errorf(MaxReplicasLowerBoundExceededError)
- }
- if minReplicas > maxReplicas && maxReplicas != 0 {
- return fmt.Errorf(MinReplicasShouldBeLessThanMaxError)
+ if endpoint.Explainer != nil {
+ if err := endpoint.Explainer.Validate(); err != nil {
+ return err
+ }
}
return nil
}
diff --git a/pkg/apis/serving/v1alpha2/kfservice_validation_test.go b/pkg/apis/serving/v1alpha2/kfservice_validation_test.go
index eeadb114577..f7314dc30c2 100644
--- a/pkg/apis/serving/v1alpha2/kfservice_validation_test.go
+++ b/pkg/apis/serving/v1alpha2/kfservice_validation_test.go
@@ -110,14 +110,14 @@ func TestRejectMultipleModelSpecs(t *testing.T) {
g := gomega.NewGomegaWithT(t)
kfsvc := makeTestKFService()
kfsvc.Spec.Default.Predictor.Custom = &CustomSpec{Container: v1.Container{}}
- g.Expect(kfsvc.ValidateCreate()).Should(gomega.MatchError(ExactlyOneModelSpecViolatedError))
+ g.Expect(kfsvc.ValidateCreate()).Should(gomega.MatchError(ExactlyOnePredictorViolatedError))
}
func TestRejectModelSpecMissing(t *testing.T) {
g := gomega.NewGomegaWithT(t)
kfsvc := makeTestKFService()
kfsvc.Spec.Default.Predictor.Tensorflow = nil
- g.Expect(kfsvc.ValidateCreate()).Should(gomega.MatchError(AtLeastOneModelSpecViolatedError))
+ g.Expect(kfsvc.ValidateCreate()).Should(gomega.MatchError(ExactlyOnePredictorViolatedError))
}
func TestRejectMultipleCanaryModelSpecs(t *testing.T) {
g := gomega.NewGomegaWithT(t)
@@ -128,7 +128,7 @@ func TestRejectMultipleCanaryModelSpecs(t *testing.T) {
Tensorflow: kfsvc.Spec.Default.Predictor.Tensorflow,
},
}
- g.Expect(kfsvc.ValidateCreate()).Should(gomega.MatchError(ExactlyOneModelSpecViolatedError))
+ g.Expect(kfsvc.ValidateCreate()).Should(gomega.MatchError(ExactlyOnePredictorViolatedError))
}
func TestRejectCanaryModelSpecMissing(t *testing.T) {
@@ -137,7 +137,7 @@ func TestRejectCanaryModelSpecMissing(t *testing.T) {
kfsvc.Spec.Canary = &EndpointSpec{
Predictor: PredictorSpec{},
}
- g.Expect(kfsvc.ValidateCreate()).Should(gomega.MatchError(AtLeastOneModelSpecViolatedError))
+ g.Expect(kfsvc.ValidateCreate()).Should(gomega.MatchError(ExactlyOnePredictorViolatedError))
}
func TestRejectBadCanaryTrafficValues(t *testing.T) {
g := gomega.NewGomegaWithT(t)
@@ -197,3 +197,17 @@ func TestCustomOK(t *testing.T) {
fmt.Println(err)
g.Expect(kfsvc.ValidateCreate()).Should(gomega.Succeed())
}
+
+func TestRejectBadTransformer(t *testing.T) {
+ g := gomega.NewGomegaWithT(t)
+ kfsvc := makeTestKFService()
+ kfsvc.Spec.Default.Transformer = &TransformerSpec{}
+ g.Expect(kfsvc.ValidateCreate()).Should(gomega.MatchError(ExactlyOneTransformerViolatedError))
+}
+
+func TestRejectBadExplainer(t *testing.T) {
+ g := gomega.NewGomegaWithT(t)
+ kfsvc := makeTestKFService()
+ kfsvc.Spec.Default.Explainer = &ExplainerSpec{}
+ g.Expect(kfsvc.ValidateCreate()).Should(gomega.MatchError(ExactlyOneExplainerViolatedError))
+}
diff --git a/pkg/apis/serving/v1alpha2/openapi_generated.go b/pkg/apis/serving/v1alpha2/openapi_generated.go
index 6ac1f5ecc9c..1316e28dd67 100644
--- a/pkg/apis/serving/v1alpha2/openapi_generated.go
+++ b/pkg/apis/serving/v1alpha2/openapi_generated.go
@@ -233,62 +233,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
Dependencies: []string{
"github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.ExplainerConfig"},
},
- "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig": {
- Schema: spec.Schema{
- SchemaProps: spec.SchemaProps{
- Properties: map[string]spec.Schema{
- "image": {
- SchemaProps: spec.SchemaProps{
- Type: []string{"string"},
- Format: "",
- },
- },
- },
- Required: []string{"image"},
- },
- },
- Dependencies: []string{},
- },
- "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworksConfig": {
- Schema: spec.Schema{
- SchemaProps: spec.SchemaProps{
- Properties: map[string]spec.Schema{
- "tensorflow": {
- SchemaProps: spec.SchemaProps{
- Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"),
- },
- },
- "tensorrt": {
- SchemaProps: spec.SchemaProps{
- Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"),
- },
- },
- "xgboost": {
- SchemaProps: spec.SchemaProps{
- Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"),
- },
- },
- "sklearn": {
- SchemaProps: spec.SchemaProps{
- Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"),
- },
- },
- "pytorch": {
- SchemaProps: spec.SchemaProps{
- Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"),
- },
- },
- "onnx": {
- SchemaProps: spec.SchemaProps{
- Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"),
- },
- },
- },
- },
- },
- Dependencies: []string{
- "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"},
- },
"github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.KFService": {
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
@@ -502,6 +446,22 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
Dependencies: []string{
"k8s.io/api/core/v1.ResourceRequirements"},
},
+ "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorConfig": {
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Properties: map[string]spec.Schema{
+ "image": {
+ SchemaProps: spec.SchemaProps{
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ },
+ Required: []string{"image"},
+ },
+ },
+ Dependencies: []string{},
+ },
"github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorSpec": {
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
@@ -570,6 +530,46 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
Dependencies: []string{
"github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.CustomSpec", "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.ONNXSpec", "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PyTorchSpec", "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.SKLearnSpec", "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.TensorRTSpec", "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.TensorflowSpec", "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.XGBoostSpec"},
},
+ "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorsConfig": {
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Properties: map[string]spec.Schema{
+ "tensorflow": {
+ SchemaProps: spec.SchemaProps{
+ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorConfig"),
+ },
+ },
+ "tensorrt": {
+ SchemaProps: spec.SchemaProps{
+ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorConfig"),
+ },
+ },
+ "xgboost": {
+ SchemaProps: spec.SchemaProps{
+ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorConfig"),
+ },
+ },
+ "sklearn": {
+ SchemaProps: spec.SchemaProps{
+ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorConfig"),
+ },
+ },
+ "pytorch": {
+ SchemaProps: spec.SchemaProps{
+ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorConfig"),
+ },
+ },
+ "onnx": {
+ SchemaProps: spec.SchemaProps{
+ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorConfig"),
+ },
+ },
+ },
+ },
+ },
+ Dependencies: []string{
+ "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorConfig"},
+ },
"github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PyTorchSpec": {
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
diff --git a/pkg/apis/serving/v1alpha2/predictor.go b/pkg/apis/serving/v1alpha2/predictor.go
new file mode 100644
index 00000000000..5c7b845d846
--- /dev/null
+++ b/pkg/apis/serving/v1alpha2/predictor.go
@@ -0,0 +1,192 @@
+/*
+Copyright 2019 kubeflow.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.
+*/
+
+package v1alpha2
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+
+ "github.com/kubeflow/kfserving/pkg/constants"
+ v1 "k8s.io/api/core/v1"
+ resource "k8s.io/apimachinery/pkg/api/resource"
+)
+
+type Predictor interface {
+ GetStorageUri() string
+ GetContainer(modelName string, config *PredictorsConfig) *v1.Container
+ ApplyDefaults()
+ Validate() error
+}
+
+const (
+ // ExactlyOnePredictorViolatedError is a known error message
+ ExactlyOnePredictorViolatedError = "Exactly one of [Custom, ONNX, Tensorflow, TensorRT, SKLearn, XGBoost] must be specified in PredictorSpec"
+)
+
+var (
+ DefaultMemory = resource.MustParse("2Gi")
+ DefaultCPU = resource.MustParse("1")
+)
+
+// Returns a URI to the model. This URI is passed to the storage-initializer via the StorageInitializerSourceUriInternalAnnotationKey
+func (p *PredictorSpec) GetStorageUri() string {
+ predictor, err := getPredictor(p)
+ if err != nil {
+ return ""
+ }
+ return predictor.GetStorageUri()
+}
+
+func (p *PredictorSpec) GetContainer(modelName string, config *PredictorsConfig) *v1.Container {
+ predictor, err := getPredictor(p)
+ if err != nil {
+ return nil
+ }
+ return predictor.GetContainer(modelName, config)
+}
+
+func (p *PredictorSpec) ApplyDefaults() {
+ predictor, err := getPredictor(p)
+ if err == nil {
+ predictor.ApplyDefaults()
+ }
+}
+
+func (p *PredictorSpec) Validate() error {
+ predictor, err := getPredictor(p)
+ if err != nil {
+ return err
+ }
+ if err := predictor.Validate(); err != nil {
+ return err
+ }
+ if err := validateStorageURI(p.GetStorageUri()); err != nil {
+ return err
+ }
+ if err := validateReplicas(p.MinReplicas, p.MaxReplicas); err != nil {
+ return err
+ }
+ return nil
+}
+
+type PredictorConfig struct {
+ ContainerImage string `json:"image"`
+
+ //TODO add readiness/liveness probe config
+}
+type PredictorsConfig struct {
+ Tensorflow PredictorConfig `json:"tensorflow,omitempty"`
+ TensorRT PredictorConfig `json:"tensorrt,omitempty"`
+ Xgboost PredictorConfig `json:"xgboost,omitempty"`
+ SKlearn PredictorConfig `json:"sklearn,omitempty"`
+ PyTorch PredictorConfig `json:"pytorch,omitempty"`
+ ONNX PredictorConfig `json:"onnx,omitempty"`
+}
+
+func validateStorageURI(storageURI string) error {
+ if storageURI == "" {
+ return nil
+ }
+
+ // local path (not some protocol?)
+ if !regexp.MustCompile("\\w+?://").MatchString(storageURI) {
+ return nil
+ }
+
+ // one of the prefixes we know?
+ for _, prefix := range SupportedStorageURIPrefixList {
+ if strings.HasPrefix(storageURI, prefix) {
+ return nil
+ }
+ }
+
+ azureURIMatcher := regexp.MustCompile(AzureBlobURIRegEx)
+ if parts := azureURIMatcher.FindStringSubmatch(storageURI); parts != nil {
+ return nil
+ }
+
+ return fmt.Errorf(UnsupportedStorageURIFormatError, strings.Join(SupportedStorageURIPrefixList, ", "), storageURI)
+}
+
+func validateReplicas(minReplicas int, maxReplicas int) error {
+ if minReplicas < 0 {
+ return fmt.Errorf(MinReplicasLowerBoundExceededError)
+ }
+ if maxReplicas < 0 {
+ return fmt.Errorf(MaxReplicasLowerBoundExceededError)
+ }
+ if minReplicas > maxReplicas && maxReplicas != 0 {
+ return fmt.Errorf(MinReplicasShouldBeLessThanMaxError)
+ }
+ return nil
+}
+
+func setResourceRequirementDefaults(requirements *v1.ResourceRequirements) {
+ if requirements.Requests == nil {
+ requirements.Requests = v1.ResourceList{}
+ }
+
+ if _, ok := requirements.Requests[v1.ResourceCPU]; !ok {
+ requirements.Requests[v1.ResourceCPU] = DefaultCPU
+ }
+ if _, ok := requirements.Requests[v1.ResourceMemory]; !ok {
+ requirements.Requests[v1.ResourceMemory] = DefaultMemory
+ }
+
+ if requirements.Limits == nil {
+ requirements.Limits = v1.ResourceList{}
+ }
+
+ if _, ok := requirements.Limits[v1.ResourceCPU]; !ok {
+ requirements.Limits[v1.ResourceCPU] = DefaultCPU
+ }
+ if _, ok := requirements.Limits[v1.ResourceMemory]; !ok {
+ requirements.Limits[v1.ResourceMemory] = DefaultMemory
+ }
+}
+
+func isGPUEnabled(requirements v1.ResourceRequirements) bool {
+ _, ok := requirements.Limits[constants.NvidiaGPUResourceType]
+ return ok
+}
+
+func getPredictor(predictorSpec *PredictorSpec) (Predictor, error) {
+ predictors := []Predictor{}
+ if predictorSpec.Custom != nil {
+ predictors = append(predictors, predictorSpec.Custom)
+ }
+ if predictorSpec.XGBoost != nil {
+ predictors = append(predictors, predictorSpec.XGBoost)
+ }
+ if predictorSpec.SKLearn != nil {
+ predictors = append(predictors, predictorSpec.SKLearn)
+ }
+ if predictorSpec.Tensorflow != nil {
+ predictors = append(predictors, predictorSpec.Tensorflow)
+ }
+ if predictorSpec.ONNX != nil {
+ predictors = append(predictors, predictorSpec.ONNX)
+ }
+ if predictorSpec.PyTorch != nil {
+ predictors = append(predictors, predictorSpec.PyTorch)
+ }
+ if predictorSpec.TensorRT != nil {
+ predictors = append(predictors, predictorSpec.TensorRT)
+ }
+ if len(predictors) != 1 {
+ return nil, fmt.Errorf(ExactlyOnePredictorViolatedError)
+ }
+ return predictors[0], nil
+}
diff --git a/pkg/apis/serving/v1alpha2/swagger.json b/pkg/apis/serving/v1alpha2/swagger.json
index 151679d1a20..8cba73b236d 100644
--- a/pkg/apis/serving/v1alpha2/swagger.json
+++ b/pkg/apis/serving/v1alpha2/swagger.json
@@ -174,38 +174,6 @@
}
}
},
- "v1alpha2.FrameworkConfig": {
- "required": [
- "image"
- ],
- "properties": {
- "image": {
- "type": "string"
- }
- }
- },
- "v1alpha2.FrameworksConfig": {
- "properties": {
- "onnx": {
- "$ref": "#/definitions/v1alpha2.FrameworkConfig"
- },
- "pytorch": {
- "$ref": "#/definitions/v1alpha2.FrameworkConfig"
- },
- "sklearn": {
- "$ref": "#/definitions/v1alpha2.FrameworkConfig"
- },
- "tensorflow": {
- "$ref": "#/definitions/v1alpha2.FrameworkConfig"
- },
- "tensorrt": {
- "$ref": "#/definitions/v1alpha2.FrameworkConfig"
- },
- "xgboost": {
- "$ref": "#/definitions/v1alpha2.FrameworkConfig"
- }
- }
- },
"v1alpha2.KFService": {
"description": "KFService is the Schema for the services API",
"properties": {
@@ -328,6 +296,16 @@
}
}
},
+ "v1alpha2.PredictorConfig": {
+ "required": [
+ "image"
+ ],
+ "properties": {
+ "image": {
+ "type": "string"
+ }
+ }
+ },
"v1alpha2.PredictorSpec": {
"description": "PredictorSpec defines the configuration to route traffic to a predictor.",
"properties": {
@@ -369,6 +347,28 @@
}
}
},
+ "v1alpha2.PredictorsConfig": {
+ "properties": {
+ "onnx": {
+ "$ref": "#/definitions/v1alpha2.PredictorConfig"
+ },
+ "pytorch": {
+ "$ref": "#/definitions/v1alpha2.PredictorConfig"
+ },
+ "sklearn": {
+ "$ref": "#/definitions/v1alpha2.PredictorConfig"
+ },
+ "tensorflow": {
+ "$ref": "#/definitions/v1alpha2.PredictorConfig"
+ },
+ "tensorrt": {
+ "$ref": "#/definitions/v1alpha2.PredictorConfig"
+ },
+ "xgboost": {
+ "$ref": "#/definitions/v1alpha2.PredictorConfig"
+ }
+ }
+ },
"v1alpha2.PyTorchSpec": {
"description": "PyTorchSpec defines arguments for configuring PyTorch model serving.",
"required": [
diff --git a/pkg/apis/serving/v1alpha2/transformer.go b/pkg/apis/serving/v1alpha2/transformer.go
new file mode 100644
index 00000000000..5a018d57cb7
--- /dev/null
+++ b/pkg/apis/serving/v1alpha2/transformer.go
@@ -0,0 +1,69 @@
+package v1alpha2
+
+import (
+ "fmt"
+
+ "github.com/kubeflow/kfserving/pkg/constants"
+ v1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/klog"
+)
+
+// Constants
+const (
+ ExactlyOneTransformerViolatedError = "Exactly one of [Custom, Feast] must be specified in TransformerSpec"
+)
+
+// Transformer interface is implemented by all Transformers
+type Transformer interface {
+ GetContainerSpec() *v1.Container
+ ApplyDefaults()
+ Validate() error
+}
+
+// GetContainerSpec for the transformer
+func (t *TransformerSpec) GetContainerSpec(metadata metav1.ObjectMeta, isCanary bool) *v1.Container {
+ transformer, err := getTransformer(t)
+ if err != nil {
+ return &v1.Container{}
+ }
+ container := transformer.GetContainerSpec().DeepCopy()
+ container.Args = append(container.Args, []string{
+ constants.ArgumentModelName,
+ metadata.Name,
+ constants.ArgumentPredictorHost,
+ constants.PredictorURL(metadata, isCanary),
+ }...)
+ return container
+}
+
+// ApplyDefaults to the TransformerSpec
+func (t *TransformerSpec) ApplyDefaults() {
+ transformer, err := getTransformer(t)
+ if err == nil {
+ transformer.ApplyDefaults()
+ }
+}
+
+// Validate the TransformerSpec
+func (t *TransformerSpec) Validate() error {
+ transformer, err := getTransformer(t)
+ if err != nil {
+ return err
+ }
+ return transformer.Validate()
+}
+
+func getTransformer(t *TransformerSpec) (Transformer, error) {
+ transformers := []Transformer{}
+ if t.Custom != nil {
+ transformers = append(transformers, t.Custom)
+ }
+ // Fail if not exactly one
+ if len(transformers) != 1 {
+ err := fmt.Errorf(ExactlyOneTransformerViolatedError)
+ klog.Error(err)
+ return nil, err
+ }
+ return transformers[0], nil
+}
diff --git a/pkg/apis/serving/v1alpha2/transformer_custom.go b/pkg/apis/serving/v1alpha2/transformer_custom.go
new file mode 100644
index 00000000000..0afb06994b5
--- /dev/null
+++ b/pkg/apis/serving/v1alpha2/transformer_custom.go
@@ -0,0 +1,12 @@
+package v1alpha2
+
+import (
+ v1 "k8s.io/api/core/v1"
+)
+
+var _ Transformer = (*CustomSpec)(nil)
+
+// GetContainerSpec for the CustomSpec
+func (c *CustomSpec) GetContainerSpec() *v1.Container {
+ return &c.Container
+}
diff --git a/pkg/apis/serving/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/serving/v1alpha2/zz_generated.deepcopy.go
index 7732f8def5f..adcde0c6b79 100644
--- a/pkg/apis/serving/v1alpha2/zz_generated.deepcopy.go
+++ b/pkg/apis/serving/v1alpha2/zz_generated.deepcopy.go
@@ -199,44 +199,6 @@ func (in *ExplainersConfig) DeepCopy() *ExplainersConfig {
return out
}
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FrameworkConfig) DeepCopyInto(out *FrameworkConfig) {
- *out = *in
- return
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FrameworkConfig.
-func (in *FrameworkConfig) DeepCopy() *FrameworkConfig {
- if in == nil {
- return nil
- }
- out := new(FrameworkConfig)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FrameworksConfig) DeepCopyInto(out *FrameworksConfig) {
- *out = *in
- out.Tensorflow = in.Tensorflow
- out.TensorRT = in.TensorRT
- out.Xgboost = in.Xgboost
- out.SKlearn = in.SKlearn
- out.PyTorch = in.PyTorch
- out.ONNX = in.ONNX
- return
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FrameworksConfig.
-func (in *FrameworksConfig) DeepCopy() *FrameworksConfig {
- if in == nil {
- return nil
- }
- out := new(FrameworksConfig)
- in.DeepCopyInto(out)
- return out
-}
-
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KFService) DeepCopyInto(out *KFService) {
*out = *in
@@ -392,6 +354,22 @@ func (in *ONNXSpec) DeepCopy() *ONNXSpec {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PredictorConfig) DeepCopyInto(out *PredictorConfig) {
+ *out = *in
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PredictorConfig.
+func (in *PredictorConfig) DeepCopy() *PredictorConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(PredictorConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PredictorSpec) DeepCopyInto(out *PredictorSpec) {
*out = *in
@@ -444,6 +422,28 @@ func (in *PredictorSpec) DeepCopy() *PredictorSpec {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PredictorsConfig) DeepCopyInto(out *PredictorsConfig) {
+ *out = *in
+ out.Tensorflow = in.Tensorflow
+ out.TensorRT = in.TensorRT
+ out.Xgboost = in.Xgboost
+ out.SKlearn = in.SKlearn
+ out.PyTorch = in.PyTorch
+ out.ONNX = in.ONNX
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PredictorsConfig.
+func (in *PredictorsConfig) DeepCopy() *PredictorsConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(PredictorsConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PyTorchSpec) DeepCopyInto(out *PyTorchSpec) {
*out = *in
diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go
index 624b5a63e1c..7647cced8cc 100644
--- a/pkg/constants/constants.go
+++ b/pkg/constants/constants.go
@@ -17,10 +17,12 @@ limitations under the License.
package constants
import (
+ "fmt"
"os"
"strings"
"k8s.io/api/admissionregistration/v1beta1"
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// KFServing Constants
@@ -107,8 +109,8 @@ const (
// KFService model server args
const (
- ModelServerArgsModelName = "--model_name"
- ModelServerArgsPredictorHost = "--predictor_host"
+ ArgumentModelName = "--model_name"
+ ArgumentPredictorHost = "--predictor_host"
)
func (e KFServiceEndpoint) String() string {
@@ -169,3 +171,10 @@ func CanaryServiceName(name string, endpoint KFServiceEndpoint) string {
func RouteName(name string, verb KFServiceVerb) string {
return name + "-" + verb.String()
}
+
+func PredictorURL(metadata v1.ObjectMeta, isCanary bool) string {
+ if isCanary {
+ return fmt.Sprintf("http://%s.%s.svc.cluster.local", CanaryPredictorServiceName(metadata.Name), metadata.Namespace)
+ }
+ return fmt.Sprintf("http://%s.%s.svc.cluster.local", DefaultPredictorServiceName(metadata.Name), metadata.Namespace)
+}
diff --git a/pkg/controller/kfservice/kfservice_controller_test.go b/pkg/controller/kfservice/kfservice_controller_test.go
index 17d94f4fe42..0046b1e5e50 100644
--- a/pkg/controller/kfservice/kfservice_controller_test.go
+++ b/pkg/controller/kfservice/kfservice_controller_test.go
@@ -47,7 +47,7 @@ var c client.Client
const timeout = time.Second * 10
var configs = map[string]string{
- "frameworks": `{
+ "predictors": `{
"tensorflow" : {
"image" : "tensorflow/serving"
},
diff --git a/pkg/controller/kfservice/resources/knative/service.go b/pkg/controller/kfservice/resources/knative/service.go
index 174412f6675..5618b91a094 100644
--- a/pkg/controller/kfservice/resources/knative/service.go
+++ b/pkg/controller/kfservice/resources/knative/service.go
@@ -34,7 +34,7 @@ import (
)
const (
- FrameworkConfigKeyName = "frameworks"
+ PredictorConfigKeyName = "predictors"
ExplainerConfigKeyName = "explainers"
)
@@ -46,15 +46,15 @@ var serviceAnnotationDisallowedList = []string{
}
type ServiceBuilder struct {
- frameworksConfig *v1alpha2.FrameworksConfig
+ frameworksConfig *v1alpha2.PredictorsConfig
credentialBuilder *credentials.CredentialBuilder
explainersConfig *v1alpha2.ExplainersConfig
}
func NewServiceBuilder(client client.Client, config *v1.ConfigMap) *ServiceBuilder {
- frameworkConfig := &v1alpha2.FrameworksConfig{}
+ frameworkConfig := &v1alpha2.PredictorsConfig{}
explainerConfig := &v1alpha2.ExplainersConfig{}
- if fmks, ok := config.Data[FrameworkConfigKeyName]; ok {
+ if fmks, ok := config.Data[PredictorConfigKeyName]; ok {
err := json.Unmarshal([]byte(fmks), &frameworkConfig)
if err != nil {
panic(fmt.Errorf("Unable to unmarshall framework json string due to %v ", err))
@@ -166,7 +166,7 @@ func (c *ServiceBuilder) CreatePredictorService(name string, metadata metav1.Obj
PodSpec: v1.PodSpec{
ServiceAccountName: predictorSpec.ServiceAccountName,
Containers: []v1.Container{
- *predictorSpec.CreateModelServingContainer(metadata.Name, c.frameworksConfig),
+ *predictorSpec.GetContainer(metadata.Name, c.frameworksConfig),
},
},
},
@@ -216,9 +216,9 @@ func (c *ServiceBuilder) CreateTransformerService(name string, metadata metav1.O
}
container := transformerSpec.Custom.Container
predefinedArgs := []string{
- constants.ModelServerArgsModelName,
+ constants.ArgumentModelName,
metadata.Name,
- constants.ModelServerArgsPredictorHost,
+ constants.ArgumentPredictorHost,
predictorHostName,
}
container.Args = append(container.Args, predefinedArgs...)
@@ -317,7 +317,7 @@ func (c *ServiceBuilder) CreateExplainerService(name string, metadata metav1.Obj
PodSpec: v1.PodSpec{
ServiceAccountName: explainerSpec.ServiceAccountName,
Containers: []v1.Container{
- *explainerSpec.CreateExplainerServingContainer(metadata.Name, predictorService, c.explainersConfig),
+ *explainerSpec.CreateExplainerContainer(metadata.Name, predictorService, c.explainersConfig),
},
},
},
diff --git a/pkg/controller/kfservice/resources/knative/service_test.go b/pkg/controller/kfservice/resources/knative/service_test.go
index d6640fbb459..79bf27afd28 100644
--- a/pkg/controller/kfservice/resources/knative/service_test.go
+++ b/pkg/controller/kfservice/resources/knative/service_test.go
@@ -55,7 +55,7 @@ var kfsvc = v1alpha2.KFService{
}
var configMapData = map[string]string{
- "frameworks": `{
+ "predictors": `{
"tensorflow" : {
"image" : "tensorflow/tfserving"
},
@@ -571,9 +571,9 @@ func TestTransformerToKnativeService(t *testing.T) {
{
Image: "transformer:latest",
Args: []string{
- constants.ModelServerArgsModelName,
+ constants.ArgumentModelName,
kfsvc.Name,
- constants.ModelServerArgsPredictorHost,
+ constants.ArgumentPredictorHost,
constants.DefaultPredictorServiceName(kfsvc.Name) + "." + kfsvc.Namespace,
},
},
@@ -612,9 +612,9 @@ func TestTransformerToKnativeService(t *testing.T) {
{
Image: "transformer:v2",
Args: []string{
- constants.ModelServerArgsModelName,
+ constants.ArgumentModelName,
kfsvc.Name,
- constants.ModelServerArgsPredictorHost,
+ constants.ArgumentPredictorHost,
constants.CanaryPredictorServiceName(kfsvc.Name) + "." + kfsvc.Namespace,
},
},
@@ -752,9 +752,9 @@ func TestExplainerToKnativeService(t *testing.T) {
{
Image: "alibi:latest",
Args: []string{
- constants.ModelServerArgsModelName,
+ constants.ArgumentModelName,
kfsvc.Name,
- constants.ModelServerArgsPredictorHost,
+ constants.ArgumentPredictorHost,
constants.DefaultPredictorServiceName(kfsvc.Name) + "." + kfsvc.Namespace,
string(v1alpha2.AlibiAnchorsTabularExplainer),
},
@@ -791,9 +791,9 @@ func TestExplainerToKnativeService(t *testing.T) {
{
Image: "alibi:latest",
Args: []string{
- constants.ModelServerArgsModelName,
+ constants.ArgumentModelName,
kfsvc.Name,
- constants.ModelServerArgsPredictorHost,
+ constants.ArgumentPredictorHost,
constants.CanaryPredictorServiceName(kfsvc.Name) + "." + kfsvc.Namespace,
string(v1alpha2.AlibiAnchorsTabularExplainer),
},