Skip to content

Commit

Permalink
Merge pull request #39 from Kuadrant/generation-gatewayapi
Browse files Browse the repository at this point in the history
Adds Gateway API HTTPRoute integration
  • Loading branch information
jjaferson authored Feb 3, 2022
2 parents 369b4c3 + 57f8323 commit 8ebb58b
Show file tree
Hide file tree
Showing 9 changed files with 338 additions and 6 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ go install github.com/kuadrant/kuadrantctl@latest
* [Generate Istio virtualservice objects](doc/generate-istio-virtualservice.md)
* [Generate Istio authenticationpolicy objects](doc/generate-istio-authorizationpolicy.md)
* [Generate kuadrat authconfig objects](doc/generate-kuadrant-authconfig.md)
* [Generate Gateway API HTTPRoute objects](doc/generate-gateway-api-httproute.md)


## Contributing
The [Development guide](doc/development.md) describes how to build the kuadrantctl CLI and how to test your changes before submitting a patch or opening a PR.
Expand Down
1 change: 1 addition & 0 deletions cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func generateCommand() *cobra.Command {

cmd.AddCommand(generateIstioCommand())
cmd.AddCommand(generateKuadrantCommand())
cmd.AddCommand(generateGatewayAPICommand())

return cmd
}
17 changes: 17 additions & 0 deletions cmd/generate_gatewayapi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cmd

import (
"github.com/spf13/cobra"
)

func generateGatewayAPICommand() *cobra.Command {
cmd := &cobra.Command{
Use: "gatewayapi",
Short: "Generate Gataway API resources",
Long: "Generate Gataway API resources",
}

cmd.AddCommand(generateGatewayApiHttpRouteCommand())

return cmd
}
161 changes: 161 additions & 0 deletions cmd/generate_gatewayapi_httproute.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package cmd

import (
"encoding/json"
"fmt"

"github.com/getkin/kin-openapi/openapi3"
"github.com/kuadrant/kuadrantctl/pkg/gatewayapi"
"github.com/kuadrant/kuadrantctl/pkg/utils"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
)

var (
generateGatewayAPIHTTPRouteOAS string
generateGatewayAPIHTTPRouteHost string
generateGatewayAPIHTTPRouteSvcName string
generateGatewayAPIHTTPRouteSvcNamespace string
generateGatewayAPIHTTPRouteSvcPort int32
generateGatewayAPIHTTPRouteGateways []string
)

//kuadrantctl generate istio virtualservice --namespace myns --oas petstore.yaml --public-host www.kuadrant.io --service-name myservice --gateway kuadrant-gateway
// --namespace myns
// --service-name myservice
// --public-host www.kuadrant.io
// --gateway kuadrant-gateway
// -- service-port 80

func generateGatewayApiHttpRouteCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "httproute",
Short: "Generate Gateway API HTTPRoute from OpenAPI 3.x",
Long: "Generate Gateway API HTTPRoute from OpenAPI 3.x",
RunE: func(cmd *cobra.Command, args []string) error {
return generateGatewayApiHttpRoute(cmd, args)
},
}

// OpenAPI ref
cmd.Flags().StringVar(&generateGatewayAPIHTTPRouteOAS, "oas", "", "/path/to/file.[json|yaml|yml] OR http[s]://domain/resource/path.[json|yaml|yml] OR - (required)")
err := cmd.MarkFlagRequired("oas")
if err != nil {
panic(err)
}

// service ref
cmd.Flags().StringVar(&generateGatewayAPIHTTPRouteSvcName, "service-name", "", "Service name (required)")
err = cmd.MarkFlagRequired("service-name")
if err != nil {
panic(err)
}

// service namespace
cmd.Flags().StringVarP(&generateGatewayAPIHTTPRouteSvcNamespace, "namespace", "n", "", "Service namespace (required)")
err = cmd.MarkFlagRequired("namespace")
if err != nil {
panic(err)
}

// service host
cmd.Flags().StringVar(&generateGatewayAPIHTTPRouteHost, "public-host", "", "Public host (required)")
err = cmd.MarkFlagRequired("public-host")
if err != nil {
panic(err)
}

// service port
cmd.Flags().Int32VarP(&generateGatewayAPIHTTPRouteSvcPort, "port", "p", 80, "Service Port (required)")

// gateway
cmd.Flags().StringSliceVar(&generateGatewayAPIHTTPRouteGateways, "gateway", []string{}, "Gateways (required)")
err = cmd.MarkFlagRequired("gateway")
if err != nil {
panic(err)
}

return cmd
}

func generateGatewayApiHttpRoute(cmd *cobra.Command, args []string) error {
oasDataRaw, err := utils.ReadExternalResource(generateGatewayAPIHTTPRouteOAS)
if err != nil {
return err
}

openapiLoader := openapi3.NewLoader()
doc, err := openapiLoader.LoadFromData(oasDataRaw)
if err != nil {
return err
}

err = doc.Validate(openapiLoader.Context)
if err != nil {
return fmt.Errorf("OpenAPI validation error: %w", err)
}

httpRoute, err := generateGatewayAPIHTTPRoute(cmd, doc)
if err != nil {
return err
}

jsonData, err := json.Marshal(httpRoute)
if err != nil {
return err
}

fmt.Fprintln(cmd.OutOrStdout(), string(jsonData))
return nil
}

func generateGatewayAPIHTTPRoute(cmd *cobra.Command, doc *openapi3.T) (*gatewayapiv1alpha2.HTTPRoute, error) {

//loop through gateway
// https://github.com/getkin/kin-openapi
gatewaysRef := []gatewayapiv1alpha2.ParentRef{}
for _, gateway := range generateGatewayAPIHTTPRouteGateways {
gatewaysRef = append(gatewaysRef, gatewayapiv1alpha2.ParentRef{
Name: gatewayapiv1alpha2.ObjectName(gateway),
})
}

port := gatewayapiv1alpha2.PortNumber(generateGatewayAPIHTTPRouteSvcPort)
service := fmt.Sprintf("%s.%s.svc", generateGatewayAPIHTTPRouteSvcName, generateGatewayAPIHTTPRouteSvcNamespace)
matches, err := gatewayapi.HTTPRouteMatchesFromOAS(doc)
if err != nil {
return nil, err
}

httpRoute := gatewayapiv1alpha2.HTTPRoute{
TypeMeta: v1.TypeMeta{
Kind: "HTTPRoute",
APIVersion: "gateway.networking.k8s.io/v1alpha2",
},
Spec: gatewayapiv1alpha2.HTTPRouteSpec{
CommonRouteSpec: gatewayapiv1alpha2.CommonRouteSpec{
ParentRefs: gatewaysRef,
},
Hostnames: []gatewayapiv1alpha2.Hostname{
gatewayapiv1alpha2.Hostname(generateGatewayAPIHTTPRouteHost),
},
Rules: []gatewayapiv1alpha2.HTTPRouteRule{
{
BackendRefs: []gatewayapiv1alpha2.HTTPBackendRef{
{
BackendRef: gatewayapiv1alpha2.BackendRef{
BackendObjectReference: gatewayapiv1alpha2.BackendObjectReference{
Name: gatewayapiv1alpha2.ObjectName(service),
Port: &port,
},
},
},
},
Matches: matches,
},
},
},
}
return &httpRoute, nil
}
35 changes: 35 additions & 0 deletions doc/generate-gataway-api-httproute.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## Generate Gateway API HTTPRoute object

The `kuadrantctl generate gatewayapi httproute` command generates an [Gateway API HTTPRoute](https://gateway-api.sigs.k8s.io/v1alpha2/guides/http-routing/)
from your [OpenAPI Specification (OAS) 3.x](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.2.md) and kubernetes service information.

### OpenAPI specification

OpenAPI document resource can be provided by one of the following channels:
* Filename in the available path.
* URL format (supported schemes are HTTP and HTTPS). The CLI will try to download from the given address.
* Read from stdin standard input stream.

### Usage :

```shell
$ kuadrantctl generate gatewayapi httproute -h
Generate Gateway API HTTPRoute from OpenAPI 3.x

Usage:
kuadrantctl generate gatewayapi httproute [flags]

Flags:
--gateway strings Gateways (required)
-h, --help help for httproute
-n, --namespace string Service namespace (required)
--oas string /path/to/file.[json|yaml|yml] OR http[s]://domain/resource/path.[json|yaml|yml] OR - (required)
-p, --port int32 Service Port (required) (default 80)
--public-host string Public host (required)
--service-name string Service name (required)

Global Flags:
-v, --verbose verbose output
```

> Under the example folder there are examples of OAS 3 that can be used to generate the resources
31 changes: 31 additions & 0 deletions examples/oas3/gateway-api-petstore.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
openapi: "3.0.0"
info:
title: "Pet Store API"
version: "1.0.0"
servers:
- url: https://toplevel.example.io/v1
paths:
/cat:
get:
parameters:
- in: header
name: X-username
required: true
schema:
type: string
operationId: "getCat"
responses:
405:
description: "invalid input"
post:
operationId: "postCat"
responses:
405:
description: "invalid input"
/dog:
get:
operationId: "getDog"
responses:
405:
description: "invalid input"
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ require (
k8s.io/apimachinery v0.22.1
k8s.io/client-go v0.22.1
sigs.k8s.io/controller-runtime v0.10.0
sigs.k8s.io/gateway-api v0.3.0
sigs.k8s.io/gateway-api v0.4.1
sigs.k8s.io/yaml v1.2.0
)
Loading

0 comments on commit 8ebb58b

Please sign in to comment.