diff --git a/config/default/crds/serving_v1alpha2_kfservice.yaml b/config/default/crds/serving_v1alpha2_kfservice.yaml index 59cf5afda29..c46fb1ca1e1 100644 --- a/config/default/crds/serving_v1alpha2_kfservice.yaml +++ b/config/default/crds/serving_v1alpha2_kfservice.yaml @@ -7,16 +7,16 @@ metadata: name: kfservices.serving.kubeflow.org spec: additionalPrinterColumns: - - JSONPath: .status.conditions[?(@.type=='Ready')].status - name: Ready - type: string - JSONPath: .status.url name: URL type: string - - JSONPath: .status.default.traffic + - JSONPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - JSONPath: .status.default.predictor.traffic name: Default Traffic type: integer - - JSONPath: .status.canary.traffic + - JSONPath: .status.canary.predictor.traffic name: Canary Traffic type: integer - JSONPath: .metadata.creationTimestamp @@ -454,15 +454,6 @@ spec: status: properties: canary: - properties: - name: - type: string - replicas: - format: int64 - type: integer - traffic: - format: int64 - type: integer type: object conditions: description: Conditions the latest available observations of a resource's @@ -499,15 +490,6 @@ spec: type: object type: array default: - properties: - name: - type: string - replicas: - format: int64 - type: integer - traffic: - format: int64 - type: integer type: object observedGeneration: description: ObservedGeneration is the 'Generation' of the Service that diff --git a/pkg/apis/serving/v1alpha2/kfservice_status.go b/pkg/apis/serving/v1alpha2/kfservice_status.go index 29cfb1e9f5a..e712e51c1e5 100644 --- a/pkg/apis/serving/v1alpha2/kfservice_status.go +++ b/pkg/apis/serving/v1alpha2/kfservice_status.go @@ -24,12 +24,36 @@ import ( const ( // RoutesReady is set when network configuration has completed. RoutesReady apis.ConditionType = "RoutesReady" + // PredictRoutesReady is set when network configuration has completed for predict endpoint verb. + PredictRoutesReady apis.ConditionType = "PredictRoutesReady" + // ExplainRoutesReady is set when network configuration has completed for explain endpoint verb. + ExplainRoutesReady apis.ConditionType = "ExplainRoutesReady" // DefaultPredictorReady is set when default predictor has reported readiness. DefaultPredictorReady apis.ConditionType = "DefaultPredictorReady" // CanaryPredictorReady is set when canary predictor has reported readiness. CanaryPredictorReady apis.ConditionType = "CanaryPredictorReady" + // DefaultExplainerReady is set when default explainer has reported readiness. + DefaultExplainerReady apis.ConditionType = "DefaultExplainerReady" + // CanaryExplainerReady is set when canary explainer has reported readiness. + CanaryExplainerReady apis.ConditionType = "CanaryExplainerReady" + // DefaultTransformerReady is set when default transformer has reported readiness. + DefaultTransformerReady apis.ConditionType = "DefaultTransformerReady" + // CanaryTransformerReady is set when canary transformer has reported readiness. + CanaryTransformerReady apis.ConditionType = "CanaryTransformerReady" ) +var defaultConditionsMap = map[constants.KFServiceEndpoint]apis.ConditionType{ + constants.Predictor: DefaultPredictorReady, + constants.Explainer: DefaultExplainerReady, + constants.Transformer: DefaultTransformerReady, +} + +var canaryConditionsMap = map[constants.KFServiceEndpoint]apis.ConditionType{ + constants.Predictor: CanaryPredictorReady, + constants.Explainer: CanaryExplainerReady, + constants.Transformer: CanaryTransformerReady, +} + // KFService Ready condition is depending on default predictor and route readiness condition // canary readiness condition only present when canary is used and currently does // not affect KFService readiness condition. @@ -54,61 +78,63 @@ func (ss *KFServiceStatus) GetCondition(t apis.ConditionType) *apis.Condition { return conditionSet.Manage(ss).GetCondition(t) } +// PropagateDefaultStatus propagates the status for the default spec func (ss *KFServiceStatus) PropagateDefaultStatus(endpoint constants.KFServiceEndpoint, defaultStatus *knservingv1alpha1.ServiceStatus) { - switch endpoint { - case constants.Predictor: - ss.PropagateDefaultPredictorStatus(defaultStatus) - case constants.Explainer: - case constants.Transformer: + if ss.Default == nil { + emptyStatusMap := make(EndpointStatusMap) + ss.Default = &emptyStatusMap } + conditionType := defaultConditionsMap[endpoint] + statusSpec, ok := (*ss.Default)[endpoint] + if !ok { + statusSpec = &StatusConfigurationSpec{} + (*ss.Default)[endpoint] = statusSpec + } + ss.propagateStatus(statusSpec, conditionType, defaultStatus) } +// PropagateCanaryStatus propagates the status for the canary spec func (ss *KFServiceStatus) PropagateCanaryStatus(endpoint constants.KFServiceEndpoint, canaryStatus *knservingv1alpha1.ServiceStatus) { - switch endpoint { - case constants.Predictor: - ss.PropagateCanaryPredictorStatus(canaryStatus) - case constants.Explainer: - case constants.Transformer: + + conditionType := canaryConditionsMap[endpoint] + + // reset status if canaryServiceStatus is nil + if canaryStatus == nil { + emptyStatusMap := make(EndpointStatusMap) + ss.Canary = &emptyStatusMap + conditionSet.Manage(ss).ClearCondition(conditionType) + return } -} -// PropagateDefaultPredictorStatus propagates the default predictor status and applies its values -// to the Service status. -func (ss *KFServiceStatus) PropagateDefaultPredictorStatus(defaultStatus *knservingv1alpha1.ServiceStatus) { - ss.Default.Name = defaultStatus.LatestCreatedRevisionName - serviceCondition := defaultStatus.GetCondition(knservingv1alpha1.ServiceConditionReady) + if ss.Canary == nil { + emptyStatusMap := make(EndpointStatusMap) + ss.Canary = &emptyStatusMap + } - switch { - case serviceCondition == nil: - case serviceCondition.Status == v1.ConditionUnknown: - conditionSet.Manage(ss).MarkUnknown(DefaultPredictorReady, serviceCondition.Reason, serviceCondition.Message) - case serviceCondition.Status == v1.ConditionTrue: - conditionSet.Manage(ss).MarkTrue(DefaultPredictorReady) - case serviceCondition.Status == v1.ConditionFalse: - conditionSet.Manage(ss).MarkFalse(DefaultPredictorReady, serviceCondition.Reason, serviceCondition.Message) + statusSpec, ok := (*ss.Canary)[endpoint] + if !ok { + statusSpec = &StatusConfigurationSpec{} + (*ss.Canary)[endpoint] = statusSpec } + + ss.propagateStatus(statusSpec, conditionType, canaryStatus) } -// PropagateCanaryPredictorStatus propagates the canary predictor status and applies its values -// to the Service status. -func (ss *KFServiceStatus) PropagateCanaryPredictorStatus(canaryStatus *knservingv1alpha1.ServiceStatus) { - // reset status if canaryServiceStatus is nil - if canaryStatus == nil { - ss.Canary = StatusConfigurationSpec{} - conditionSet.Manage(ss).ClearCondition(CanaryPredictorReady) - return +func (ss *KFServiceStatus) propagateStatus(statusSpec *StatusConfigurationSpec, conditionType apis.ConditionType, serviceStatus *knservingv1alpha1.ServiceStatus) { + statusSpec.Name = serviceStatus.LatestCreatedRevisionName + if serviceStatus.URL != nil { + statusSpec.Hostname = serviceStatus.URL.Host } - ss.Canary.Name = canaryStatus.LatestCreatedRevisionName - serviceCondition := canaryStatus.GetCondition(knservingv1alpha1.ServiceConditionReady) + serviceCondition := serviceStatus.GetCondition(knservingv1alpha1.ServiceConditionReady) switch { case serviceCondition == nil: case serviceCondition.Status == v1.ConditionUnknown: - conditionSet.Manage(ss).MarkUnknown(CanaryPredictorReady, serviceCondition.Reason, serviceCondition.Message) + conditionSet.Manage(ss).MarkUnknown(conditionType, serviceCondition.Reason, serviceCondition.Message) case serviceCondition.Status == v1.ConditionTrue: - conditionSet.Manage(ss).MarkTrue(CanaryPredictorReady) + conditionSet.Manage(ss).MarkTrue(conditionType) case serviceCondition.Status == v1.ConditionFalse: - conditionSet.Manage(ss).MarkFalse(CanaryPredictorReady, serviceCondition.Reason, serviceCondition.Message) + conditionSet.Manage(ss).MarkFalse(conditionType, serviceCondition.Reason, serviceCondition.Message) } } @@ -116,15 +142,8 @@ func (ss *KFServiceStatus) PropagateCanaryPredictorStatus(canaryStatus *knservin func (ss *KFServiceStatus) PropagateRouteStatus(rs *knservingv1alpha1.RouteStatus) { ss.URL = rs.URL.String() - for _, traffic := range rs.Traffic { - switch traffic.RevisionName { - case ss.Default.Name: - ss.Default.Traffic = traffic.Percent - case ss.Canary.Name: - ss.Canary.Traffic = traffic.Percent - default: - } - } + propagateRouteStatus(rs, ss.Default) + propagateRouteStatus(rs, ss.Canary) rc := rs.GetCondition(knservingv1alpha1.RouteConditionReady) @@ -138,3 +157,16 @@ func (ss *KFServiceStatus) PropagateRouteStatus(rs *knservingv1alpha1.RouteStatu conditionSet.Manage(ss).MarkFalse(RoutesReady, rc.Reason, rc.Message) } } + +func propagateRouteStatus(rs *knservingv1alpha1.RouteStatus, endpointStatusMap *EndpointStatusMap) { + for _, traffic := range rs.Traffic { + for _, endpoint := range *endpointStatusMap { + if endpoint.Name == traffic.RevisionName { + endpoint.Traffic = traffic.Percent + if traffic.URL != nil { + endpoint.Hostname = traffic.URL.Host + } + } + } + } +} diff --git a/pkg/apis/serving/v1alpha2/kfservice_status_test.go b/pkg/apis/serving/v1alpha2/kfservice_status_test.go index 4c783d02d84..83a07d7f195 100644 --- a/pkg/apis/serving/v1alpha2/kfservice_status_test.go +++ b/pkg/apis/serving/v1alpha2/kfservice_status_test.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha2 import ( + "github.com/kubeflow/kfserving/pkg/constants" "k8s.io/api/core/v1" "knative.dev/pkg/apis/duck" duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" @@ -196,8 +197,8 @@ func TestKFServiceIsReady(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { status := KFServiceStatus{} - status.PropagateDefaultPredictorStatus(&tc.defaultServiceStatus) - status.PropagateCanaryPredictorStatus(&tc.canaryServiceStatus) + status.PropagateDefaultStatus(constants.Predictor, &tc.defaultServiceStatus) + status.PropagateCanaryStatus(constants.Predictor, &tc.canaryServiceStatus) status.PropagateRouteStatus(&tc.routeStatus) if e, a := tc.isReady, status.IsReady(); e != a { t.Errorf("%q expected: %v got: %v", tc.name, e, a) diff --git a/pkg/apis/serving/v1alpha2/kfservice_types.go b/pkg/apis/serving/v1alpha2/kfservice_types.go index efcf86e23ac..61d35e8bf0a 100644 --- a/pkg/apis/serving/v1alpha2/kfservice_types.go +++ b/pkg/apis/serving/v1alpha2/kfservice_types.go @@ -14,6 +14,7 @@ limitations under the License. package v1alpha2 import ( + "github.com/kubeflow/kfserving/pkg/constants" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" @@ -182,17 +183,21 @@ type CustomSpec struct { Container v1.Container `json:"container"` } +// EndpointStatusMap defines the observed state of KFService endpoints +type EndpointStatusMap map[constants.KFServiceEndpoint]*StatusConfigurationSpec + // KFServiceStatus defines the observed state of KFService type KFServiceStatus struct { duckv1beta1.Status `json:",inline"` - URL string `json:"url,omitempty"` - Default StatusConfigurationSpec `json:"default,omitempty"` - Canary StatusConfigurationSpec `json:"canary,omitempty"` + URL string `json:"url,omitempty"` + Default *EndpointStatusMap `json:"default,omitempty"` + Canary *EndpointStatusMap `json:"canary,omitempty"` } // StatusConfigurationSpec describes the state of the configuration receiving traffic. type StatusConfigurationSpec struct { Name string `json:"name,omitempty"` + Hostname string `json:"host,omitempty"` Replicas int `json:"replicas,omitempty"` Traffic int `json:"traffic,omitempty"` } @@ -202,10 +207,10 @@ type StatusConfigurationSpec struct { // KFService is the Schema for the services API // +k8s:openapi-gen=true -// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status" // +kubebuilder:printcolumn:name="URL",type="string",JSONPath=".status.url" -// +kubebuilder:printcolumn:name="Default Traffic",type="integer",JSONPath=".status.default.traffic" -// +kubebuilder:printcolumn:name="Canary Traffic",type="integer",JSONPath=".status.canary.traffic" +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status" +// +kubebuilder:printcolumn:name="Default Traffic",type="integer",JSONPath=".status.default.predictor.traffic" +// +kubebuilder:printcolumn:name="Canary Traffic",type="integer",JSONPath=".status.canary.predictor.traffic" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" // +kubebuilder:resource:path=kfservices,shortName=kfservice type KFService struct { diff --git a/pkg/apis/serving/v1alpha2/kfservice_types_test.go b/pkg/apis/serving/v1alpha2/kfservice_types_test.go index f30a3a09701..24e080fc82a 100644 --- a/pkg/apis/serving/v1alpha2/kfservice_types_test.go +++ b/pkg/apis/serving/v1alpha2/kfservice_types_test.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha2 import ( + "github.com/kubeflow/kfserving/pkg/constants" "testing" "github.com/onsi/gomega" @@ -84,15 +85,19 @@ func TestKFService(t *testing.T) { statusUpdated := fetched.DeepCopy() statusUpdated.Status = KFServiceStatus{ URL: "example.dev.com", - Default: StatusConfigurationSpec{ - Name: "v1", - Traffic: 20, - Replicas: 2, + Default: &EndpointStatusMap{ + constants.Predictor: &StatusConfigurationSpec{ + Name: "v1", + Traffic: 20, + Replicas: 2, + }, }, - Canary: StatusConfigurationSpec{ - Name: "v2", - Traffic: 80, - Replicas: 3, + Canary: &EndpointStatusMap{ + constants.Predictor: &StatusConfigurationSpec{ + Name: "v2", + Traffic: 80, + Replicas: 3, + }, }, } g.Expect(c.Update(context.TODO(), statusUpdated)).NotTo(gomega.HaveOccurred()) diff --git a/pkg/apis/serving/v1alpha2/openapi_generated.go b/pkg/apis/serving/v1alpha2/openapi_generated.go index c472d49ca71..6ac1f5ecc9c 100644 --- a/pkg/apis/serving/v1alpha2/openapi_generated.go +++ b/pkg/apis/serving/v1alpha2/openapi_generated.go @@ -23,51 +23,51 @@ limitations under the License. package v1alpha2 import ( - openapispec "github.com/go-openapi/spec" + spec "github.com/go-openapi/spec" common "k8s.io/kube-openapi/pkg/common" ) func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { return map[string]common.OpenAPIDefinition{ "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.AlibiExplainerSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "AlibiExplainerSpec defines the arguments for configuring an Alibi Explanation Server", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "type": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "The type of Alibi explainer", Type: []string{"string"}, Format: "", }, }, "storageUri": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "The location of a trained explanation model", Type: []string{"string"}, Format: "", }, }, "runtimeVersion": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to latest Alibi Version.", Type: []string{"string"}, Format: "", }, }, "resources": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to requests and limits of 1CPU, 2Gb MEM.", Ref: ref("k8s.io/api/core/v1.ResourceRequirements"), }, }, "config": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Inline custom parameter settings for explainer", Type: []string{"object"}, - AdditionalProperties: &openapispec.SchemaOrBool{ - Schema: &openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + AdditionalProperties: &spec.SchemaOrBool{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ Type: []string{"string"}, Format: "", }, @@ -83,12 +83,12 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.ResourceRequirements"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.CustomSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "CustomSpec provides a hook for arbitrary container configuration.", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "container": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("k8s.io/api/core/v1.Container"), }, }, @@ -100,26 +100,26 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.Container"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.DeploymentSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "DeploymentSpec defines the configuration for a given KFService service component", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "serviceAccountName": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "ServiceAccountName is the name of the ServiceAccount to use to run the service", Type: []string{"string"}, Format: "", }, }, "minReplicas": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Minimum number of replicas, pods won't scale down to 0 in case of no traffic", Type: []string{"integer"}, Format: "int32", }, }, "maxReplicas": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "This is the up bound for autoscaler to scale to", Type: []string{"integer"}, Format: "int32", @@ -131,23 +131,23 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA Dependencies: []string{}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.EndpointSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ - Properties: map[string]openapispec.Schema{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Properties: map[string]spec.Schema{ "predictor": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Predictor defines the model serving spec", Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorSpec"), }, }, "explainer": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Explainer defines the model explanation service spec explainer service calls to transformer or predictor service", Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.ExplainerSpec"), }, }, "transformer": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Transformer defines the transformer service spec for pre/post processing transformer service calls to predictor service", Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.TransformerSpec"), }, @@ -160,11 +160,11 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.ExplainerSpec", "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorSpec", "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.TransformerSpec"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.ExplainerConfig": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ - Properties: map[string]openapispec.Schema{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Properties: map[string]spec.Schema{ "image": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Type: []string{"string"}, Format: "", }, @@ -176,37 +176,37 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA Dependencies: []string{}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.ExplainerSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "ExplainerSpec defines the arguments for a model explanation server", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "alibi": { - SchemaProps: openapispec.SchemaProps{ - Description: "The following fields follow a \"1-of\" semantic. Users must specify exactly one openapispec.", + SchemaProps: spec.SchemaProps{ + Description: "The following fields follow a \"1-of\" semantic. Users must specify exactly one spec.", Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.AlibiExplainerSpec"), }, }, "custom": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.CustomSpec"), }, }, "serviceAccountName": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "ServiceAccountName is the name of the ServiceAccount to use to run the service", Type: []string{"string"}, Format: "", }, }, "minReplicas": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Minimum number of replicas, pods won't scale down to 0 in case of no traffic", Type: []string{"integer"}, Format: "int32", }, }, "maxReplicas": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "This is the up bound for autoscaler to scale to", Type: []string{"integer"}, Format: "int32", @@ -219,11 +219,11 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.AlibiExplainerSpec", "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.CustomSpec"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.ExplainersConfig": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ - Properties: map[string]openapispec.Schema{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Properties: map[string]spec.Schema{ "alibi": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.ExplainerConfig"), }, }, @@ -234,11 +234,11 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.ExplainerConfig"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ - Properties: map[string]openapispec.Schema{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Properties: map[string]spec.Schema{ "image": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Type: []string{"string"}, Format: "", }, @@ -250,36 +250,36 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA Dependencies: []string{}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworksConfig": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ - Properties: map[string]openapispec.Schema{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Properties: map[string]spec.Schema{ "tensorflow": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"), }, }, "tensorrt": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"), }, }, "xgboost": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"), }, }, "sklearn": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"), }, }, "pytorch": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"), }, }, "onnx": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"), }, }, @@ -290,36 +290,36 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.FrameworkConfig"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.KFService": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "KFService is the Schema for the services API", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "kind": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", Type: []string{"string"}, Format: "", }, }, "apiVersion": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", Type: []string{"string"}, Format: "", }, }, "metadata": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), }, }, "spec": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.KFServiceSpec"), }, }, "status": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.KFServiceStatus"), }, }, @@ -330,35 +330,35 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.KFServiceSpec", "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.KFServiceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.KFServiceList": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "KFServiceList contains a list of Service", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "kind": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", Type: []string{"string"}, Format: "", }, }, "apiVersion": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", Type: []string{"string"}, Format: "", }, }, "metadata": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), }, }, "items": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Type: []string{"array"}, - Items: &openapispec.SchemaOrArray{ - Schema: &openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.KFService"), }, }, @@ -373,24 +373,24 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.KFService", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.KFServiceSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "KFServiceSpec defines the desired state of KFService", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "default": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Default defines default KFService endpoints", Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.EndpointSpec"), }, }, "canary": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Canary defines an alternate endpoints to route a percentage of traffic.", Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.EndpointSpec"), }, }, "canaryTrafficPercent": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "CanaryTrafficPercent defines the percentage of traffic going to canary KFService endpoints", Type: []string{"integer"}, Format: "int32", @@ -404,30 +404,30 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.EndpointSpec"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.KFServiceStatus": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "KFServiceStatus defines the observed state of KFService", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "observedGeneration": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "ObservedGeneration is the 'Generation' of the Service that was last processed by the controller.", Type: []string{"integer"}, Format: "int64", }, }, "conditions": { - VendorExtensible: openapispec.VendorExtensible{ - Extensions: openapispec.Extensions{ + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ "x-kubernetes-patch-merge-key": "type", "x-kubernetes-patch-strategy": "merge", }, }, - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Conditions the latest available observations of a resource's current state.", Type: []string{"array"}, - Items: &openapispec.SchemaOrArray{ - Schema: &openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ Ref: ref("knative.dev/pkg/apis.Condition"), }, }, @@ -435,19 +435,33 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA }, }, "url": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Type: []string{"string"}, Format: "", }, }, "default": { - SchemaProps: openapispec.SchemaProps{ - Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.StatusConfigurationSpec"), + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.StatusConfigurationSpec"), + }, + }, + }, }, }, "canary": { - SchemaProps: openapispec.SchemaProps{ - Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.StatusConfigurationSpec"), + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.StatusConfigurationSpec"), + }, + }, + }, }, }, }, @@ -457,26 +471,26 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.StatusConfigurationSpec", "knative.dev/pkg/apis.Condition"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.ONNXSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "ONNXSpec defines arguments for configuring ONNX model serving.", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "storageUri": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "The location of the trained model", Type: []string{"string"}, Format: "", }, }, "runtimeVersion": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to latest ONNX Version.", Type: []string{"string"}, Format: "", }, }, "resources": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to requests and limits of 1CPU, 2Gb MEM.", Ref: ref("k8s.io/api/core/v1.ResourceRequirements"), }, @@ -489,62 +503,62 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.ResourceRequirements"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PredictorSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "PredictorSpec defines the configuration to route traffic to a predictor.", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "custom": { - SchemaProps: openapispec.SchemaProps{ - Description: "The following fields follow a \"1-of\" semantic. Users must specify exactly one openapispec.", + SchemaProps: spec.SchemaProps{ + Description: "The following fields follow a \"1-of\" semantic. Users must specify exactly one spec.", Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.CustomSpec"), }, }, "tensorflow": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.TensorflowSpec"), }, }, "tensorrt": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.TensorRTSpec"), }, }, "xgboost": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.XGBoostSpec"), }, }, "sklearn": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.SKLearnSpec"), }, }, "onnx": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.ONNXSpec"), }, }, "pytorch": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.PyTorchSpec"), }, }, "serviceAccountName": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "ServiceAccountName is the name of the ServiceAccount to use to run the service", Type: []string{"string"}, Format: "", }, }, "minReplicas": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Minimum number of replicas, pods won't scale down to 0 in case of no traffic", Type: []string{"integer"}, Format: "int32", }, }, "maxReplicas": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "This is the up bound for autoscaler to scale to", Type: []string{"integer"}, Format: "int32", @@ -557,33 +571,33 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "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.PyTorchSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "PyTorchSpec defines arguments for configuring PyTorch model serving.", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "storageUri": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "The location of the trained model", Type: []string{"string"}, Format: "", }, }, "modelClassName": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults PyTorch model class name to 'PyTorchModel'", Type: []string{"string"}, Format: "", }, }, "runtimeVersion": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to latest PyTorch Version", Type: []string{"string"}, Format: "", }, }, "resources": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to requests and limits of 1CPU, 2Gb MEM.", Ref: ref("k8s.io/api/core/v1.ResourceRequirements"), }, @@ -596,26 +610,26 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.ResourceRequirements"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.SKLearnSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "SKLearnSpec defines arguments for configuring SKLearn model serving.", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "storageUri": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "The location of the trained model", Type: []string{"string"}, Format: "", }, }, "runtimeVersion": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to latest SKLearn Version.", Type: []string{"string"}, Format: "", }, }, "resources": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to requests and limits of 1CPU, 2Gb MEM.", Ref: ref("k8s.io/api/core/v1.ResourceRequirements"), }, @@ -628,24 +642,30 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.ResourceRequirements"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.StatusConfigurationSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "StatusConfigurationSpec describes the state of the configuration receiving traffic.", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "name": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "host": { + SchemaProps: spec.SchemaProps{ Type: []string{"string"}, Format: "", }, }, "replicas": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Type: []string{"integer"}, Format: "int32", }, }, "traffic": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Type: []string{"integer"}, Format: "int32", }, @@ -656,26 +676,26 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA Dependencies: []string{}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.TensorRTSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "TensorRTSpec defines arguments for configuring TensorRT model serving.", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "storageUri": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "The location of the trained model", Type: []string{"string"}, Format: "", }, }, "runtimeVersion": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to latest TensorRT Version.", Type: []string{"string"}, Format: "", }, }, "resources": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to requests and limits of 1CPU, 2Gb MEM.", Ref: ref("k8s.io/api/core/v1.ResourceRequirements"), }, @@ -688,26 +708,26 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.ResourceRequirements"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.TensorflowSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "TensorflowSpec defines arguments for configuring Tensorflow model serving.", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "storageUri": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "The location of the trained model", Type: []string{"string"}, Format: "", }, }, "runtimeVersion": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to latest TF Version.", Type: []string{"string"}, Format: "", }, }, "resources": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to requests and limits of 1CPU, 2Gb MEM.", Ref: ref("k8s.io/api/core/v1.ResourceRequirements"), }, @@ -720,31 +740,31 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.ResourceRequirements"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.TransformerSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "TransformerSpec defines transformer service for pre/post processing", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "custom": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.CustomSpec"), }, }, "serviceAccountName": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "ServiceAccountName is the name of the ServiceAccount to use to run the service", Type: []string{"string"}, Format: "", }, }, "minReplicas": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Minimum number of replicas, pods won't scale down to 0 in case of no traffic", Type: []string{"integer"}, Format: "int32", }, }, "maxReplicas": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "This is the up bound for autoscaler to scale to", Type: []string{"integer"}, Format: "int32", @@ -757,26 +777,26 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.CustomSpec"}, }, "github.com/kubeflow/kfserving/pkg/apis/serving/v1alpha2.XGBoostSpec": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "XGBoostSpec defines arguments for configuring XGBoost model serving.", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "storageUri": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "The location of the trained model", Type: []string{"string"}, Format: "", }, }, "runtimeVersion": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to latest XGBoost Version.", Type: []string{"string"}, Format: "", }, }, "resources": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Defaults to requests and limits of 1CPU, 2Gb MEM.", Ref: ref("k8s.io/api/core/v1.ResourceRequirements"), }, @@ -789,46 +809,46 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/core/v1.ResourceRequirements"}, }, "knative.dev/pkg/apis.Condition": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "Conditions defines a readiness condition for a Knative resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "type": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Type of condition.", Type: []string{"string"}, Format: "", }, }, "status": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Status of the condition, one of True, False, Unknown.", Type: []string{"string"}, Format: "", }, }, "severity": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "Severity with which to treat failures of this type of condition. When this is not specified, it defaults to Error.", Type: []string{"string"}, Format: "", }, }, "lastTransitionTime": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "LastTransitionTime is the last time the condition transitioned from one status to another. We use VolatileTime in place of metav1.Time to exclude this from creating equality.Semantic differences (all other things held constant).", Ref: ref("knative.dev/pkg/apis.VolatileTime"), }, }, "reason": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "The reason for the condition's last transition.", Type: []string{"string"}, Format: "", }, }, "message": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Description: "A human readable message indicating details about the transition.", Type: []string{"string"}, Format: "", @@ -842,12 +862,12 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "knative.dev/pkg/apis.VolatileTime"}, }, "knative.dev/pkg/apis.VolatileTime": { - Schema: openapispec.Schema{ - SchemaProps: openapispec.SchemaProps{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ Description: "VolatileTime wraps metav1.Time", - Properties: map[string]openapispec.Schema{ + Properties: map[string]spec.Schema{ "Inner": { - SchemaProps: openapispec.SchemaProps{ + SchemaProps: spec.SchemaProps{ Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), }, }, diff --git a/pkg/apis/serving/v1alpha2/swagger.json b/pkg/apis/serving/v1alpha2/swagger.json index 1bb6227bbab..151679d1a20 100644 --- a/pkg/apis/serving/v1alpha2/swagger.json +++ b/pkg/apis/serving/v1alpha2/swagger.json @@ -145,7 +145,7 @@ "description": "ExplainerSpec defines the arguments for a model explanation server", "properties": { "alibi": { - "description": "The following fields follow a \"1-of\" semantic. Users must specify exactly one openapispec.", + "description": "The following fields follow a \"1-of\" semantic. Users must specify exactly one spec.", "$ref": "#/definitions/v1alpha2.AlibiExplainerSpec" }, "custom": { @@ -278,7 +278,10 @@ "description": "KFServiceStatus defines the observed state of KFService", "properties": { "canary": { - "$ref": "#/definitions/v1alpha2.StatusConfigurationSpec" + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/v1alpha2.StatusConfigurationSpec" + } }, "conditions": { "description": "Conditions the latest available observations of a resource's current state.", @@ -290,7 +293,10 @@ "x-kubernetes-patch-strategy": "merge" }, "default": { - "$ref": "#/definitions/v1alpha2.StatusConfigurationSpec" + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/v1alpha2.StatusConfigurationSpec" + } }, "observedGeneration": { "description": "ObservedGeneration is the 'Generation' of the Service that was last processed by the controller.", @@ -326,7 +332,7 @@ "description": "PredictorSpec defines the configuration to route traffic to a predictor.", "properties": { "custom": { - "description": "The following fields follow a \"1-of\" semantic. Users must specify exactly one openapispec.", + "description": "The following fields follow a \"1-of\" semantic. Users must specify exactly one spec.", "$ref": "#/definitions/v1alpha2.CustomSpec" }, "maxReplicas": { @@ -410,6 +416,9 @@ "v1alpha2.StatusConfigurationSpec": { "description": "StatusConfigurationSpec describes the state of the configuration receiving traffic.", "properties": { + "host": { + "type": "string" + }, "name": { "type": "string" }, diff --git a/pkg/apis/serving/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/serving/v1alpha2/zz_generated.deepcopy.go index 90e9972df2e..7732f8def5f 100644 --- a/pkg/apis/serving/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/serving/v1alpha2/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package v1alpha2 import ( + constants "github.com/kubeflow/kfserving/pkg/constants" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -108,6 +109,36 @@ func (in *EndpointSpec) DeepCopy() *EndpointSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in EndpointStatusMap) DeepCopyInto(out *EndpointStatusMap) { + { + in := &in + *out = make(EndpointStatusMap, len(*in)) + for key, val := range *in { + var outVal *StatusConfigurationSpec + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(StatusConfigurationSpec) + **out = **in + } + (*out)[key] = outVal + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EndpointStatusMap. +func (in EndpointStatusMap) DeepCopy() EndpointStatusMap { + if in == nil { + return nil + } + out := new(EndpointStatusMap) + in.DeepCopyInto(out) + return *out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ExplainerConfig) DeepCopyInto(out *ExplainerConfig) { *out = *in @@ -293,8 +324,44 @@ func (in *KFServiceSpec) DeepCopy() *KFServiceSpec { func (in *KFServiceStatus) DeepCopyInto(out *KFServiceStatus) { *out = *in in.Status.DeepCopyInto(&out.Status) - out.Default = in.Default - out.Canary = in.Canary + if in.Default != nil { + in, out := &in.Default, &out.Default + *out = new(EndpointStatusMap) + if **in != nil { + in, out := *in, *out + *out = make(map[constants.KFServiceEndpoint]*StatusConfigurationSpec, len(*in)) + for key, val := range *in { + var outVal *StatusConfigurationSpec + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(StatusConfigurationSpec) + **out = **in + } + (*out)[key] = outVal + } + } + } + if in.Canary != nil { + in, out := &in.Canary, &out.Canary + *out = new(EndpointStatusMap) + if **in != nil { + in, out := *in, *out + *out = make(map[constants.KFServiceEndpoint]*StatusConfigurationSpec, len(*in)) + for key, val := range *in { + var outVal *StatusConfigurationSpec + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(StatusConfigurationSpec) + **out = **in + } + (*out)[key] = outVal + } + } + } return } diff --git a/pkg/controller/kfservice/kfservice_controller_test.go b/pkg/controller/kfservice/kfservice_controller_test.go index 3058c34e388..17d94f4fe42 100644 --- a/pkg/controller/kfservice/kfservice_controller_test.go +++ b/pkg/controller/kfservice/kfservice_controller_test.go @@ -189,6 +189,14 @@ func TestKFServiceWithOnlyPredictor(t *testing.T) { updatedRoute := route.DeepCopy() updatedRoute.Status.URL = &apis.URL{Scheme: "http", Host: serviceKey.Name + ".svc.cluster.local"} + updatedRoute.Status.Traffic = []knservingv1alpha1.TrafficTarget{ + knservingv1alpha1.TrafficTarget{ + TrafficTarget: v1beta1.TrafficTarget{ + RevisionName: "revision-v1", + Percent: 0, + }, + }, + } updatedRoute.Status.Conditions = duckv1beta1.Conditions{ { Type: knservingv1alpha1.RouteConditionReady, @@ -216,9 +224,12 @@ func TestKFServiceWithOnlyPredictor(t *testing.T) { }, }, URL: updatedRoute.Status.URL.String(), - Default: kfserving.StatusConfigurationSpec{ - Name: "revision-v1", + Default: &kfserving.EndpointStatusMap{ + constants.Predictor: &kfserving.StatusConfigurationSpec{ + Name: "revision-v1", + }, }, + Canary: &kfserving.EndpointStatusMap{}, } g.Eventually(func() *kfserving.KFServiceStatus { kfsvc := &kfserving.KFService{} @@ -268,8 +279,10 @@ func TestKFServiceWithOnlyCanaryPredictor(t *testing.T) { }, Status: kfserving.KFServiceStatus{ URL: canaryServiceKey.Name + ".svc.cluster.local", - Default: kfserving.StatusConfigurationSpec{ - Name: "revision-v1", + Default: &kfserving.EndpointStatusMap{ + constants.Predictor: &kfserving.StatusConfigurationSpec{ + Name: "revision-v1", + }, }, }, } @@ -419,10 +432,16 @@ func TestKFServiceWithOnlyCanaryPredictor(t *testing.T) { updatedRoute.Status.URL = &apis.URL{Scheme: "http", Host: canaryServiceKey.Name + ".svc.cluster.local"} updatedRoute.Status.Traffic = []knservingv1alpha1.TrafficTarget{ { - TrafficTarget: v1beta1.TrafficTarget{RevisionName: "revision-v2", Percent: 20}, + TrafficTarget: v1beta1.TrafficTarget{ + RevisionName: "revision-v2", + Percent: 20, + }, }, { - TrafficTarget: v1beta1.TrafficTarget{RevisionName: "revision-v1", Percent: 80}, + TrafficTarget: v1beta1.TrafficTarget{ + RevisionName: "revision-v1", + Percent: 80, + }, }, } updatedRoute.Status.Conditions = duckv1beta1.Conditions{ @@ -458,15 +477,20 @@ func TestKFServiceWithOnlyCanaryPredictor(t *testing.T) { }, }, URL: updatedRoute.Status.URL.String(), - Default: kfserving.StatusConfigurationSpec{ - Name: "revision-v1", - Traffic: 80, + Default: &kfserving.EndpointStatusMap{ + constants.Predictor: &kfserving.StatusConfigurationSpec{ + Name: "revision-v1", + Traffic: 80, + }, }, - Canary: kfserving.StatusConfigurationSpec{ - Name: "revision-v2", - Traffic: 20, + Canary: &kfserving.EndpointStatusMap{ + constants.Predictor: &kfserving.StatusConfigurationSpec{ + Name: "revision-v2", + Traffic: 20, + }, }, } + time.Sleep(100 * time.Millisecond) g.Eventually(func() string { kfsvc := &kfserving.KFService{} if err := c.Get(context.TODO(), canaryServiceKey, kfsvc); err != nil { @@ -522,8 +546,10 @@ func TestCanaryDelete(t *testing.T) { }, Status: kfserving.KFServiceStatus{ URL: canaryServiceKey.Name + ".svc.cluster.local", - Default: kfserving.StatusConfigurationSpec{ - Name: "revision-v1", + Default: &kfserving.EndpointStatusMap{ + constants.Predictor: &kfserving.StatusConfigurationSpec{ + Name: "revision-v1", + }, }, }, } @@ -615,6 +641,7 @@ func TestCanaryDelete(t *testing.T) { Status: "True", }, } + g.Expect(c.Status().Update(context.TODO(), updatedRoute)).NotTo(gomega.HaveOccurred()) g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedCanaryRequest))) @@ -643,13 +670,17 @@ func TestCanaryDelete(t *testing.T) { }, }, URL: routeUrl.String(), - Default: kfserving.StatusConfigurationSpec{ - Name: "revision-v1", - Traffic: 80, + Default: &kfserving.EndpointStatusMap{ + constants.Predictor: &kfserving.StatusConfigurationSpec{ + Name: "revision-v1", + Traffic: 80, + }, }, - Canary: kfserving.StatusConfigurationSpec{ - Name: "revision-v2", - Traffic: 20, + Canary: &kfserving.EndpointStatusMap{ + constants.Predictor: &kfserving.StatusConfigurationSpec{ + Name: "revision-v2", + Traffic: 20, + }, }, } @@ -698,8 +729,10 @@ func TestCanaryDelete(t *testing.T) { }, }, URL: routeUrl.String(), - Default: kfserving.StatusConfigurationSpec{ - Name: "revision-v1", + Default: &kfserving.EndpointStatusMap{ + constants.Predictor: &kfserving.StatusConfigurationSpec{ + Name: "revision-v1", + }, }, } g.Eventually(func() *duckv1beta1.Conditions { @@ -784,8 +817,10 @@ func TestKFServiceWithTransformer(t *testing.T) { }, Status: kfserving.KFServiceStatus{ URL: serviceName + ".svc.cluster.local", - Default: kfserving.StatusConfigurationSpec{ - Name: "revision-v1", + Default: &kfserving.EndpointStatusMap{ + constants.Predictor: &kfserving.StatusConfigurationSpec{ + Name: "revision-v1", + }, }, }, } @@ -906,38 +941,76 @@ func TestKFServiceWithTransformer(t *testing.T) { g.Expect(route.Spec).To(gomega.Equal(expectedRoute.Spec)) // mock update knative service status since knative serving controller is not running in test - updateDefault := defaultPredictorService.DeepCopy() - updateDefault.Status.LatestCreatedRevisionName = "revision-v1" - updateDefault.Status.LatestReadyRevisionName = "revision-v1" - updateDefault.Status.Conditions = duckv1beta1.Conditions{ - { - Type: knservingv1alpha1.ServiceConditionReady, - Status: "True", - }, + + // update predictor + { + updateDefault := defaultPredictorService.DeepCopy() + updateDefault.Status.LatestCreatedRevisionName = "revision-v1" + updateDefault.Status.LatestReadyRevisionName = "revision-v1" + updateDefault.Status.Conditions = duckv1beta1.Conditions{ + { + Type: knservingv1alpha1.ServiceConditionReady, + Status: "True", + }, + } + g.Expect(c.Status().Update(context.TODO(), updateDefault)).NotTo(gomega.HaveOccurred()) + g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) + + updateCanary := canaryPredictorService.DeepCopy() + updateCanary.Status.LatestCreatedRevisionName = "revision-v2" + updateCanary.Status.LatestReadyRevisionName = "revision-v2" + updateCanary.Status.Conditions = duckv1beta1.Conditions{ + { + Type: knservingv1alpha1.ServiceConditionReady, + Status: "True", + }, + } + g.Expect(c.Status().Update(context.TODO(), updateCanary)).NotTo(gomega.HaveOccurred()) + g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) } - g.Expect(c.Status().Update(context.TODO(), updateDefault)).NotTo(gomega.HaveOccurred()) - g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) - updateCanary := canaryPredictorService.DeepCopy() - updateCanary.Status.LatestCreatedRevisionName = "revision-v2" - updateCanary.Status.LatestReadyRevisionName = "revision-v2" - updateCanary.Status.Conditions = duckv1beta1.Conditions{ - { - Type: knservingv1alpha1.ServiceConditionReady, - Status: "True", - }, + // update transformer + { + updateDefault := defaultTransformerService.DeepCopy() + updateDefault.Status.LatestCreatedRevisionName = "t-revision-v1" + updateDefault.Status.LatestReadyRevisionName = "t-revision-v1" + updateDefault.Status.Conditions = duckv1beta1.Conditions{ + { + Type: knservingv1alpha1.ServiceConditionReady, + Status: "True", + }, + } + g.Expect(c.Status().Update(context.TODO(), updateDefault)).NotTo(gomega.HaveOccurred()) + g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) + + updateCanary := canaryTransformerService.DeepCopy() + updateCanary.Status.LatestCreatedRevisionName = "t-revision-v2" + updateCanary.Status.LatestReadyRevisionName = "t-revision-v2" + updateCanary.Status.Conditions = duckv1beta1.Conditions{ + { + Type: knservingv1alpha1.ServiceConditionReady, + Status: "True", + }, + } + g.Expect(c.Status().Update(context.TODO(), updateCanary)).NotTo(gomega.HaveOccurred()) + g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) } - g.Expect(c.Status().Update(context.TODO(), updateCanary)).NotTo(gomega.HaveOccurred()) - g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest))) + // update route updatedRoute := route.DeepCopy() updatedRoute.Status.URL = &apis.URL{Scheme: "http", Host: serviceName + ".svc.cluster.local"} updatedRoute.Status.Traffic = []knservingv1alpha1.TrafficTarget{ { - TrafficTarget: v1beta1.TrafficTarget{RevisionName: "revision-v2", Percent: 20}, + TrafficTarget: v1beta1.TrafficTarget{ + RevisionName: "t-revision-v2", + Percent: 20, + }, }, { - TrafficTarget: v1beta1.TrafficTarget{RevisionName: "revision-v1", Percent: 80}, + TrafficTarget: v1beta1.TrafficTarget{ + RevisionName: "t-revision-v1", + Percent: 80, + }, }, } updatedRoute.Status.Conditions = duckv1beta1.Conditions{ @@ -958,10 +1031,20 @@ func TestKFServiceWithTransformer(t *testing.T) { Severity: "Info", Status: "True", }, + { + Type: kfserving.CanaryTransformerReady, + Severity: "Info", + Status: "True", + }, { Type: kfserving.DefaultPredictorReady, Status: "True", }, + { + Type: kfserving.DefaultTransformerReady, + Severity: "Info", + Status: "True", + }, { Type: apis.ConditionReady, Status: "True", @@ -973,13 +1056,23 @@ func TestKFServiceWithTransformer(t *testing.T) { }, }, URL: updatedRoute.Status.URL.String(), - Default: kfserving.StatusConfigurationSpec{ - Name: "revision-v1", - Traffic: 80, + Default: &kfserving.EndpointStatusMap{ + constants.Predictor: &kfserving.StatusConfigurationSpec{ + Name: "revision-v1", + }, + constants.Transformer: &kfserving.StatusConfigurationSpec{ + Name: "t-revision-v1", + Traffic: 80, + }, }, - Canary: kfserving.StatusConfigurationSpec{ - Name: "revision-v2", - Traffic: 20, + Canary: &kfserving.EndpointStatusMap{ + constants.Predictor: &kfserving.StatusConfigurationSpec{ + Name: "revision-v2", + }, + constants.Transformer: &kfserving.StatusConfigurationSpec{ + Name: "t-revision-v2", + Traffic: 20, + }, }, } g.Eventually(func() string { diff --git a/pkg/controller/kfservice/resources/knative/route_test.go b/pkg/controller/kfservice/resources/knative/route_test.go index c28ec8dc3df..d89b810fe7a 100644 --- a/pkg/controller/kfservice/resources/knative/route_test.go +++ b/pkg/controller/kfservice/resources/knative/route_test.go @@ -95,8 +95,10 @@ func TestKnativeRoute(t *testing.T) { }, }, Status: v1alpha2.KFServiceStatus{ - Default: v1alpha2.StatusConfigurationSpec{ - Name: "v1", + Default: &v1alpha2.EndpointStatusMap{ + constants.Predictor: &v1alpha2.StatusConfigurationSpec{ + Name: "v1", + }, }, }, }, @@ -155,8 +157,10 @@ func TestKnativeRoute(t *testing.T) { }, }, Status: v1alpha2.KFServiceStatus{ - Default: v1alpha2.StatusConfigurationSpec{ - Name: "v1", + Default: &v1alpha2.EndpointStatusMap{ + constants.Predictor: &v1alpha2.StatusConfigurationSpec{ + Name: "v1", + }, }, }, }, diff --git a/pkg/controller/kfservice/resources/knative/service_test.go b/pkg/controller/kfservice/resources/knative/service_test.go index f9f85b9fba9..d6640fbb459 100644 --- a/pkg/controller/kfservice/resources/knative/service_test.go +++ b/pkg/controller/kfservice/resources/knative/service_test.go @@ -205,8 +205,10 @@ func TestKFServiceToKnativeService(t *testing.T) { }, }, Status: v1alpha2.KFServiceStatus{ - Default: v1alpha2.StatusConfigurationSpec{ - Name: "v1", + Default: &v1alpha2.EndpointStatusMap{ + constants.Predictor: &v1alpha2.StatusConfigurationSpec{ + Name: "v1", + }, }, }, },