This document will guide you through the process of creating a concrete resource converter that implements the Provider
interface in the i2gw package.
Each provider implementation in the i2gw/providers package is responsible for converting a provider specific Ingress
and related resources (e.g istio VirtualService) into Gateway API resources.
A provider must be able to read its custom resources, and convert them.
- Familiarity with Go programming language.
- Basic understanding of Kubernetes and its custom resources.
- A setup Go development environment.
In this section, we will walk through a demo of how to add support for the example-gateway provider.
- Add a new package under the
providerspackage. Say we want to add a new gateway provider example.
.
├── ingress2gateway.go
├── ingress2gateway_test.go
├── provider.go
└── providers
├── common
├── examplegateway
└── ingressnginx
- Create a struct named
resourceReaderwhich implements theCustomResourceReaderinterface in a file namedresource_converter.go.
package examplegateway
import (
"context"
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw"
)
// converter implements the i2gw.CustomResourceReader interface.
type resourceReader struct {
conf *i2gw.ProviderConf
}
// newResourceReader returns a resourceReader instance.
func newResourceReader(conf *i2gw.ProviderConf) *resourceReader {
return &resourceReader{
conf: conf,
}
}
func (r *resourceReader) ReadResourcesFromCluster(ctx context.Context) error {
// read example-gateway related resources from the cluster.
return nil
}
func (r *resourceReader) ReadResourcesFromFiles(ctx context.Context, filename string) error {
// read example-gateway related resources from the file.
return nil
}These methods are used by providers to read and store additional resources they may need during conversion.
- Create a struct named
converterwhich implements theResourceConverterinterface in a file namedconverter.go. The implementedToGatewayAPIfunction should simply call every registeredfeatureParserfunction, one by one. Take a look atingressnginx/converter.gofor an example. TheImplementationSpecificOptionsstruct contains the handlers to customize native ingress implementation-specific fields. Take a look atkong/converter.gofor an example.
package examplegateway
import (
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw"
)
// converter implements the ToGatewayAPI function of i2gw.ResourceConverter interface.
type converter struct {
conf *i2gw.ProviderConf
featureParsers []i2gw.FeatureParser
implementationSpecificOptions i2gw.ProviderImplementationSpecificOptions
}
// newConverter returns an ingress-nginx converter instance.
func newConverter(conf *i2gw.ProviderConf) *converter {
return &converter{
conf: conf,
featureParsers: []i2gw.FeatureParser{
// The list of feature parsers comes here.
},
implementationSpecificOptions: i2gw.ProviderImplementationSpecificOptions{
// The list of the implementationSpecific ingress fields options comes here.
},
}
}- Create a new struct named after the provider you are implementing. This struct should embed the previous 2 structs you created.
package examplegateway
import (
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw"
)
// Provider implements the i2gw.Provider interface.
type Provider struct {
conf *i2gw.ProviderConf
*resourceReader
*converter
}
// NewProvider constructs and returns the example-gateway implementation of i2gw.Provider.
func NewProvider(conf *i2gw.ProviderConf) i2gw.Provider {
return &Provider{
conf: conf,
resourceReader: newResourceReader(conf),
converter: newConverter(conf),
}
}- Add the new provider to
i2gw.ProviderConstructorByName.
package examplegateway
import (
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw"
)
// The Name of the provider.
const Name = "example-gateway-provider"
func init() {
i2gw.ProviderConstructorByName[Name] = NewProvider
}- [optional] In order to use notification mechanism, create a
notifyfunction in a file namednotification.go. This method is used to reduce the function signature for creating notifications during the conversion process.
package examplegateway
import "github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/notifications"
func notify(mType notifications.MessageType, message string) {
newNotification := notifications.Notification{Type: mType, Message: message}
notifications.CommonNotification.DispatchNotication(newNotification, string(ProviderName))
}- Import the new package at
cmd/print.
package cmd
import (
// Call init function for the providers
_ "github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/providers/ingressnginx"
_ "github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/providers/examplegateway"
)In case you want to add support for the conversion of a specific feature within a provider (see for example the canary
feature of ingress-nginx) you'll want to implement a FeatureParser function.
Different FeatureParsers within the same provider will run in undetermined order. This means that when building a
Gateway API resource manifest, you cannot assume anything about previously initialized fields.
The function must modify / create only the required fields of the resource manifest and nothing else.
For example, lets say we are implementing the canary feature of some provider. When building the HTTPRoute, we cannot
assume that the BackendRefs is already initialized with every BackendRef required. The canary FeatureParser
function must add every missing BackendRef and update existing ones.
There are 2 main things that needs to be tested when creating a feature parser:
- The conversion logic is actually correct.
- The new function doesn't override other functions modifications.
For example, if one implemented the mirror backend feature and it deletes canary weight from
BackendRefs, we have a problem.
To define provider-specific flags the user can supply in the print command, call the
i2gw.RegisterProviderSpecificFlag(ProviderName, i2gw.ProviderSpecificFlag) function in the init function of the
provider. E.g.:
const Name = "example-gateway-provider"
func init() {
i2gw.ProviderConstructorByName[Name] = NewProvider
i2gw.RegisterProviderSpecificFlag(ProviderName, i2gw.ProviderSpecificFlag{
Name: "infrastructure-labels",
Description: "Comma-separated list of Gateway infrastructure key=value labels",
DefaultValue: "",
})
}Users can provide a value to the flag as follows:
./ingress2gateway print --providers=example-gateway-provider --example-gateway-provider-infrastructure-labels="app=my-app"The values of all provider-specific flags supplied by the user can be retrieved from the provider conf:
if ps := conf.ProviderSpecificFlags[ProviderName]; ps != nil {
labels := ps["infrastructure-labels"]
}