diff --git a/cmd/generate_gatewayapi_httproute.go b/cmd/generate_gatewayapi_httproute.go index 93b7960..fea188d 100644 --- a/cmd/generate_gatewayapi_httproute.go +++ b/cmd/generate_gatewayapi_httproute.go @@ -65,7 +65,7 @@ func runGenerateGatewayApiHttpRoute(cmd *cobra.Command, args []string) error { } func buildHTTPRoute(doc *openapi3.T) *gatewayapiv1beta1.HTTPRoute { - httpRoute := &gatewayapiv1beta1.HTTPRoute{ + return &gatewayapiv1beta1.HTTPRoute{ TypeMeta: v1.TypeMeta{ APIVersion: "gateway.networking.k8s.io/v1beta1", Kind: "HTTPRoute", @@ -79,12 +79,4 @@ func buildHTTPRoute(doc *openapi3.T) *gatewayapiv1beta1.HTTPRoute { Rules: gatewayapi.HTTPRouteRulesFromOAS(doc), }, } - - // Extract and set labels - labels, ok := gatewayapi.ExtractLabelsFromOAS(doc) - if ok { - httpRoute.ObjectMeta.Labels = labels - } - - return httpRoute } diff --git a/doc/openapi-kuadrant-extensions.md b/doc/openapi-kuadrant-extensions.md index f927fd4..3f2ca70 100644 --- a/doc/openapi-kuadrant-extensions.md +++ b/doc/openapi-kuadrant-extensions.md @@ -10,6 +10,8 @@ info: route: ## HTTPRoute metadata name: "petstore" namespace: "petstore" + labels: ## map[string]string + deployment: petstore hostnames: ## []gateway.networking.k8s.io/v1beta1.Hostname - example.com parentRefs: ## []gateway.networking.k8s.io/v1beta1.ParentReference @@ -27,7 +29,8 @@ is the default when there is no operation level configuration. paths: /cat: x-kuadrant: ## Path level Kuadrant Extension - enable: true ## Add to the HTTPRoute. Optional. Default: false + disable: true ## Remove from the HTTPRoute. Optional. Default: false + pathMatchType: Exact ## Specifies how to match against the path Value. Valid values: [Exact;PathPrefix]. Optional. Default: Exact backendRefs: ## Backend references to be included in the HTTPRoute. []gateway.networking.k8s.io/v1beta1.HTTPBackendRef. Optional. - name: petstore port: 80 @@ -55,7 +58,8 @@ paths: /cat: get: x-kuadrant: ## Path level Kuadrant Extension - enable: true ## Add to the HTTPRoute. Optional. Default: false + disable: true ## Remove from the HTTPRoute. Optional. Default: path level "disable" value + pathMatchType: Exact ## Specifies how to match against the path Value. Valid values: [Exact;PathPrefix]. Optional. Default: Exact backendRefs: ## Backend references to be included in the HTTPRoute. Optional. - name: petstore port: 80 diff --git a/pkg/gatewayapi/http_route.go b/pkg/gatewayapi/http_route.go index 743f8f4..68c2ea4 100644 --- a/pkg/gatewayapi/http_route.go +++ b/pkg/gatewayapi/http_route.go @@ -1,8 +1,6 @@ package gatewayapi import ( - "fmt" - "github.com/getkin/kin-openapi/openapi3" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" @@ -29,7 +27,10 @@ func HTTPRouteObjectMetaFromOAS(doc *openapi3.T) metav1.ObjectMeta { panic("info kuadrant extension route name not found") } - om := metav1.ObjectMeta{Name: *kuadrantInfoExtension.Route.Name} + om := metav1.ObjectMeta{ + Name: *kuadrantInfoExtension.Route.Name, + Labels: kuadrantInfoExtension.Route.Labels, + } if kuadrantInfoExtension.Route.Namespace != nil { om.Namespace = *kuadrantInfoExtension.Route.Namespace @@ -89,8 +90,6 @@ func HTTPRouteRulesFromOAS(doc *openapi3.T) []gatewayapiv1beta1.HTTPRouteRule { panic(err) } - pathEnabled := kuadrantPathExtension.IsEnabled() - // Operations for verb, operation := range pathItem.Operations() { kuadrantOperationExtension, err := utils.NewKuadrantOASOperationExtension(operation) @@ -98,7 +97,7 @@ func HTTPRouteRulesFromOAS(doc *openapi3.T) []gatewayapiv1beta1.HTTPRouteRule { panic(err) } - if !ptr.Deref(kuadrantOperationExtension.Enable, pathEnabled) { + if ptr.Deref(kuadrantOperationExtension.Disable, kuadrantPathExtension.IsDisabled()) { // not enabled for the operation continue } @@ -109,7 +108,13 @@ func HTTPRouteRulesFromOAS(doc *openapi3.T) []gatewayapiv1beta1.HTTPRouteRule { backendRefs = kuadrantOperationExtension.BackendRefs } - rules = append(rules, buildHTTPRouteRule(basePath, path, pathItem, verb, operation, backendRefs)) + // default pathMatchType at the path level + pathMatchType := ptr.Deref( + kuadrantOperationExtension.PathMatchType, + kuadrantPathExtension.GetPathMatchType(), + ) + + rules = append(rules, buildHTTPRouteRule(basePath, path, pathItem, verb, operation, backendRefs, pathMatchType)) } } @@ -120,30 +125,8 @@ func HTTPRouteRulesFromOAS(doc *openapi3.T) []gatewayapiv1beta1.HTTPRouteRule { return rules } -func ExtractLabelsFromOAS(doc *openapi3.T) (map[string]string, bool) { - if doc.Info == nil || doc.Info.Extensions == nil { - return nil, false - } - - if extension, ok := doc.Info.Extensions["x-kuadrant"]; ok { - if extensionMap, ok := extension.(map[string]interface{}); ok { - if route, ok := extensionMap["route"].(map[string]interface{}); ok { - if labelsInterface, ok := route["labels"]; ok { - labels := make(map[string]string) - for key, value := range labelsInterface.(map[string]interface{}) { - labels[key] = fmt.Sprint(value) - } - return labels, true - } - } - } - } - - return nil, false -} - -func buildHTTPRouteRule(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation, backendRefs []gatewayapiv1beta1.HTTPBackendRef) gatewayapiv1beta1.HTTPRouteRule { - match := utils.OpenAPIMatcherFromOASOperations(basePath, path, pathItem, verb, op) +func buildHTTPRouteRule(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation, backendRefs []gatewayapiv1beta1.HTTPBackendRef, pathMatchType gatewayapiv1beta1.PathMatchType) gatewayapiv1beta1.HTTPRouteRule { + match := utils.OpenAPIMatcherFromOASOperations(basePath, path, pathItem, verb, op, pathMatchType) return gatewayapiv1beta1.HTTPRouteRule{ BackendRefs: backendRefs, diff --git a/pkg/kuadrantapi/rate_limit_policy.go b/pkg/kuadrantapi/rate_limit_policy.go index 8941b9e..2509574 100644 --- a/pkg/kuadrantapi/rate_limit_policy.go +++ b/pkg/kuadrantapi/rate_limit_policy.go @@ -33,8 +33,6 @@ func RateLimitPolicyLimitsFromOAS(doc *openapi3.T) map[string]kuadrantapiv1beta2 panic(err) } - pathEnabled := kuadrantPathExtension.IsEnabled() - // Operations for verb, operation := range pathItem.Operations() { kuadrantOperationExtension, err := utils.NewKuadrantOASOperationExtension(operation) @@ -42,7 +40,7 @@ func RateLimitPolicyLimitsFromOAS(doc *openapi3.T) map[string]kuadrantapiv1beta2 panic(err) } - if !ptr.Deref(kuadrantOperationExtension.Enable, pathEnabled) { + if ptr.Deref(kuadrantOperationExtension.Disable, kuadrantPathExtension.IsDisabled()) { // not enabled for the operation //fmt.Printf("OUT not enabled: path: %s, method: %s\n", path, verb) continue @@ -60,10 +58,16 @@ func RateLimitPolicyLimitsFromOAS(doc *openapi3.T) map[string]kuadrantapiv1beta2 continue } + // default pathMatchType at the path level + pathMatchType := ptr.Deref( + kuadrantOperationExtension.PathMatchType, + kuadrantPathExtension.GetPathMatchType(), + ) + limitName := utils.OpenAPIOperationName(path, verb, operation) limits[limitName] = kuadrantapiv1beta2.Limit{ - RouteSelectors: buildLimitRouteSelectors(basePath, path, pathItem, verb, operation), + RouteSelectors: buildLimitRouteSelectors(basePath, path, pathItem, verb, operation, pathMatchType), When: rateLimit.When, Counters: rateLimit.Counters, Rates: rateLimit.Rates, @@ -78,8 +82,8 @@ func RateLimitPolicyLimitsFromOAS(doc *openapi3.T) map[string]kuadrantapiv1beta2 return limits } -func buildLimitRouteSelectors(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation) []kuadrantapiv1beta2.RouteSelector { - match := utils.OpenAPIMatcherFromOASOperations(basePath, path, pathItem, verb, op) +func buildLimitRouteSelectors(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation, pathMatchType gatewayapiv1beta1.PathMatchType) []kuadrantapiv1beta2.RouteSelector { + match := utils.OpenAPIMatcherFromOASOperations(basePath, path, pathItem, verb, op, pathMatchType) return []kuadrantapiv1beta2.RouteSelector{ { diff --git a/pkg/utils/kuadrant_oas_extension_types.go b/pkg/utils/kuadrant_oas_extension_types.go index 95eca2d..699fef1 100644 --- a/pkg/utils/kuadrant_oas_extension_types.go +++ b/pkg/utils/kuadrant_oas_extension_types.go @@ -14,6 +14,7 @@ type RouteObject struct { Namespace *string `json:"namespace,omitempty"` Hostnames []gatewayapiv1beta1.Hostname `json:"hostnames,omitempty"` ParentRefs []gatewayapiv1beta1.ParentReference `json:"parentRefs,omitempty"` + Labels map[string]string `json:"labels,omitempty"` } type KuadrantOASInfoExtension struct { @@ -48,14 +49,20 @@ type KuadrantRateLimitExtension struct { } type KuadrantOASPathExtension struct { - Enable *bool `json:"enable,omitempty"` - BackendRefs []gatewayapiv1beta1.HTTPBackendRef `json:"backendRefs,omitempty"` - RateLimit *KuadrantRateLimitExtension `json:"rate_limit,omitempty"` + Disable *bool `json:"disable,omitempty"` + PathMatchType *gatewayapiv1beta1.PathMatchType `json:"pathMatchType,omitempty"` + BackendRefs []gatewayapiv1beta1.HTTPBackendRef `json:"backendRefs,omitempty"` + RateLimit *KuadrantRateLimitExtension `json:"rate_limit,omitempty"` } -func (k *KuadrantOASPathExtension) IsEnabled() bool { +func (k *KuadrantOASPathExtension) IsDisabled() bool { // Set default - return ptr.Deref(k.Enable, false) + return ptr.Deref(k.Disable, false) +} + +func (k *KuadrantOASPathExtension) GetPathMatchType() gatewayapiv1beta1.PathMatchType { + // Set default + return ptr.Deref(k.PathMatchType, gatewayapiv1beta1.PathMatchExact) } func NewKuadrantOASPathExtension(pathItem *openapi3.PathItem) (*KuadrantOASPathExtension, error) { diff --git a/pkg/utils/oas_utils.go b/pkg/utils/oas_utils.go index e6ab9a2..46c55c1 100644 --- a/pkg/utils/oas_utils.go +++ b/pkg/utils/oas_utils.go @@ -97,8 +97,7 @@ func BasePathFromOpenAPI(obj *openapi3.T) (string, error) { return serverURL.Path, nil } -func OpenAPIMatcherFromOASOperations(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation) gatewayapiv1beta1.HTTPRouteMatch { - +func OpenAPIMatcherFromOASOperations(basePath, path string, pathItem *openapi3.PathItem, verb string, op *openapi3.Operation, pathMatchType gatewayapiv1beta1.PathMatchType) gatewayapiv1beta1.HTTPRouteMatch { // remove the last slash of the Base Path sanitizedBasePath := LastSlashRegexp.ReplaceAllString(basePath, "") @@ -126,8 +125,7 @@ func OpenAPIMatcherFromOASOperations(basePath, path string, pathItem *openapi3.P return gatewayapiv1beta1.HTTPRouteMatch{ Method: &[]gatewayapiv1beta1.HTTPMethod{gatewayapiv1beta1.HTTPMethod(verb)}[0], Path: &gatewayapiv1beta1.HTTPPathMatch{ - // TODO(eguzki): consider other path match types like PathPrefix - Type: &[]gatewayapiv1beta1.PathMatchType{gatewayapiv1beta1.PathMatchExact}[0], + Type: &pathMatchType, Value: &[]string{matchPath}[0], }, Headers: headersMatch,