Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: print all resources #78

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 27 additions & 83 deletions cmd/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package cmd

import (
"errors"
"fmt"
"log"
"os"
Expand All @@ -28,6 +29,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client"

// Call init function for the providers
_ "github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/providers/apisix"
Expand Down Expand Up @@ -55,6 +57,10 @@ type PrintRunner struct {
// --all-namespaces/-A flag.
allNamespaces bool

// allResources indicates whether to print all the resources instead of printing only
// the Gateway API ones. It can be used only when reading from file.
allResources bool

// resourcePrinter determines how resource objects are printed out
resourcePrinter printers.ResourcePrinter

Expand Down Expand Up @@ -82,102 +88,31 @@ func (pr *PrintRunner) PrintGatewayAPIObjects(cmd *cobra.Command, _ []string) er
return fmt.Errorf("failed to initialize namespace filter: %w", err)
}

gatewayResources, err := i2gw.ToGatewayAPIResources(cmd.Context(), pr.namespaceFilter, pr.inputFile, pr.providers, pr.getProviderSpecificFlags())
resources, err := i2gw.GetResources(cmd.Context(), pr.namespaceFilter, pr.inputFile, pr.allResources, pr.providers, pr.getProviderSpecificFlags())
if err != nil {
return err
}

pr.outputResult(gatewayResources)
pr.outputResult(resources)

return nil
}

func (pr *PrintRunner) outputResult(gatewayResources []i2gw.GatewayResources) {
resourceCount := 0

for _, r := range gatewayResources {
resourceCount += len(r.GatewayClasses)
for _, gatewayClass := range r.GatewayClasses {
gatewayClass := gatewayClass
err := pr.resourcePrinter.PrintObj(&gatewayClass, os.Stdout)
if err != nil {
fmt.Printf("# Error printing %s GatewayClass: %v\n", gatewayClass.Name, err)
}
}
}

for _, r := range gatewayResources {
resourceCount += len(r.Gateways)
for _, gateway := range r.Gateways {
gateway := gateway
err := pr.resourcePrinter.PrintObj(&gateway, os.Stdout)
if err != nil {
fmt.Printf("# Error printing %s Gateway: %v\n", gateway.Name, err)
}
}
}

for _, r := range gatewayResources {
resourceCount += len(r.HTTPRoutes)
for _, httpRoute := range r.HTTPRoutes {
httpRoute := httpRoute
err := pr.resourcePrinter.PrintObj(&httpRoute, os.Stdout)
if err != nil {
fmt.Printf("# Error printing %s HTTPRoute: %v\n", httpRoute.Name, err)
}
}
}

for _, r := range gatewayResources {
resourceCount += len(r.TLSRoutes)
for _, tlsRoute := range r.TLSRoutes {
tlsRoute := tlsRoute
err := pr.resourcePrinter.PrintObj(&tlsRoute, os.Stdout)
if err != nil {
fmt.Printf("# Error printing %s TLSRoute: %v\n", tlsRoute.Name, err)
}
}
}

for _, r := range gatewayResources {
resourceCount += len(r.TCPRoutes)
for _, tcpRoute := range r.TCPRoutes {
tcpRoute := tcpRoute
err := pr.resourcePrinter.PrintObj(&tcpRoute, os.Stdout)
if err != nil {
fmt.Printf("# Error printing %s TCPRoute: %v\n", tcpRoute.Name, err)
}
}
}

for _, r := range gatewayResources {
resourceCount += len(r.UDPRoutes)
for _, udpRoute := range r.UDPRoutes {
udpRoute := udpRoute
err := pr.resourcePrinter.PrintObj(&udpRoute, os.Stdout)
if err != nil {
fmt.Printf("# Error printing %s UDPRoute: %v\n", udpRoute.Name, err)
}
}
}

for _, r := range gatewayResources {
resourceCount += len(r.ReferenceGrants)
for _, referenceGrant := range r.ReferenceGrants {
referenceGrant := referenceGrant
err := pr.resourcePrinter.PrintObj(&referenceGrant, os.Stdout)
if err != nil {
fmt.Printf("# Error printing %s ReferenceGrant: %v\n", referenceGrant.Name, err)
}
}
}

if resourceCount == 0 {
func (pr *PrintRunner) outputResult(resources []client.Object) {
if len(resources) == 0 {
msg := "No resources found"
mlavacca marked this conversation as resolved.
Show resolved Hide resolved
if pr.namespaceFilter != "" {
msg = fmt.Sprintf("%s in %s namespace", msg, pr.namespaceFilter)
}
fmt.Println(msg)
return
}

for _, r := range resources {
err := pr.resourcePrinter.PrintObj(r, os.Stdout)
if err != nil {
fmt.Printf("# Error printing %s %s: %v\n", r.GetName(), r.GetObjectKind().GroupVersionKind().Kind, err)
}
mlavacca marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down Expand Up @@ -238,6 +173,12 @@ func newPrintCommand() *cobra.Command {
Use: "print",
Short: "Prints Gateway API objects generated from ingress and provider-specific resources.",
RunE: pr.PrintGatewayAPIObjects,
PreRunE: func(cmd *cobra.Command, args []string) error {
mlavacca marked this conversation as resolved.
Show resolved Hide resolved
if pr.allResources && pr.inputFile == "" {
return errors.New("--all-resources flag can be set only when --input-file is set")
}
return nil
},
LiorLieberman marked this conversation as resolved.
Show resolved Hide resolved
LiorLieberman marked this conversation as resolved.
Show resolved Hide resolved
}

cmd.Flags().StringVarP(&pr.outputFormat, "output", "o", "yaml",
Expand All @@ -253,6 +194,9 @@ func newPrintCommand() *cobra.Command {
`If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even
if specified with --namespace.`)

cmd.Flags().BoolVar(&pr.allResources, "all-resources", false,
`If present, list all the objects across the selected namespaces. This flag can be set only when the --input-file flag is set as well.`)

cmd.Flags().StringSliceVar(&pr.providers, "providers", i2gw.GetSupportedProviders(),
fmt.Sprintf("If present, the tool will try to convert only resources related to the specified providers, supported values are %v.", i2gw.GetSupportedProviders()))

Expand Down
77 changes: 75 additions & 2 deletions pkg/i2gw/ingress2gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ limitations under the License.
package i2gw

import (
"bytes"
"context"
"fmt"
"maps"
"os"

"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation/field"
Expand All @@ -30,7 +32,7 @@ import (
gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
)

func ToGatewayAPIResources(ctx context.Context, namespace string, inputFile string, providers []string, providerSpecificFlags map[string]map[string]string) ([]GatewayResources, error) {
func GetResources(ctx context.Context, namespace string, inputFile string, allresources bool, providers []string, providerSpecificFlags map[string]map[string]string) ([]client.Object, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we leave some version of the old name (ToGatewayAPIResources) and return []client.Object, []client.Object, error ? GetResources does not really reflect what the function is doing

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or []GatewayResources, []client.Object, error

var clusterClient client.Client

if inputFile == "" {
Expand All @@ -55,10 +57,16 @@ func ToGatewayAPIResources(ctx context.Context, namespace string, inputFile stri
return nil, err
}

var genericResources []client.Object
if inputFile != "" {
if err = readProviderResourcesFromFile(ctx, providerByName, inputFile); err != nil {
return nil, err
}
if allresources {
if genericResources, err = readGenericResourcesFromFile(inputFile, namespace, providerByName); err != nil {
return nil, err
}
}
} else {
if err = readProviderResourcesFromCluster(ctx, providerByName); err != nil {
return nil, err
Expand All @@ -78,7 +86,42 @@ func ToGatewayAPIResources(ctx context.Context, namespace string, inputFile stri
return nil, aggregatedErrs(errs)
}

return gatewayResources, nil
return append(gatewayResourcesToObjects(gatewayResources), genericResources...), nil
}

func gatewayResourcesToObjects(gatewayResources []GatewayResources) []client.Object {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a small function comment, also mention the order it returns the resources

var objects []client.Object
for _, gr := range gatewayResources {
for _, gateway := range gr.Gateways {
gateway := gateway
objects = append(objects, &gateway)
}
for _, gatewayClass := range gr.GatewayClasses {
gatewayClass := gatewayClass
objects = append(objects, &gatewayClass)
}
for _, httpRoute := range gr.HTTPRoutes {
httpRoute := httpRoute
objects = append(objects, &httpRoute)
}
for _, tlsRoute := range gr.TLSRoutes {
tlsRoute := tlsRoute
objects = append(objects, &tlsRoute)
}
for _, tcpRoute := range gr.TCPRoutes {
tcpRoute := tcpRoute
objects = append(objects, &tcpRoute)
}
for _, udpRoute := range gr.UDPRoutes {
udpRoute := udpRoute
objects = append(objects, &udpRoute)
}
for _, referenceGrant := range gr.ReferenceGrants {
referenceGrant := referenceGrant
objects = append(objects, &referenceGrant)
}
}
return objects
}

func readProviderResourcesFromFile(ctx context.Context, providerByName map[ProviderName]Provider, inputFile string) error {
Expand All @@ -90,6 +133,36 @@ func readProviderResourcesFromFile(ctx context.Context, providerByName map[Provi
return nil
}

func readGenericResourcesFromFile(inputFile, namespace string, providerByName map[ProviderName]Provider) ([]client.Object, error) {
objects := make([]client.Object, 0)
stream, err := os.ReadFile(inputFile)
if err != nil {
return nil, fmt.Errorf("failed to read file %v: %w", inputFile, err)
}

unstructuredObjects, err := ExtractObjectsFromReader(bytes.NewReader(stream), namespace)
if err != nil {
return nil, fmt.Errorf("failed to extract objects: %w", err)
}

for _, p := range providerByName {
for _, crd := range p.GetCRDs() {
FilteredResources[crd] = struct{}{}
}
}
Comment on lines +148 to +152
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haven't thought much about it, but what are your thoughts on this approach VS every provider registers the resources he cares about in init().

I am not sure what I prefer, slight preference to what you currently have but wanted to discuss this


for _, o := range unstructuredObjects {
if o.GetNamespace() != namespace {
continue
}
if _, ok := FilteredResources[o.GetObjectKind().GroupVersionKind().GroupKind()]; ok {
continue
Comment on lines +158 to +159
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to think if there is a different way to do it. I less like the fact that every provider needs to register its resources and that we depends on it.. I have not thought on anything smart yet.
But.. we should have all the resources the provider cares about (which are the resources that we need to filter out from the file) in its storage.. Maybe we can leverage that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can add a GetCRDs() method to the provider interface. We have access to all the providers in i2gw package, so we can do the registration in this package. Instead of having each one registering his own CRDs

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed @levikobi's suggestion and added a GetCRDs method to the provider interface. Let me know if it looks better now. In that case, I'll add documentation about the new method for the providers to implement.

}
objects = append(objects, o)
}
return objects, nil
}

func readProviderResourcesFromCluster(ctx context.Context, providerByName map[ProviderName]Provider) error {
for name, provider := range providerByName {
if err := provider.ReadResourcesFromCluster(ctx); err != nil {
Expand Down
4 changes: 4 additions & 0 deletions pkg/i2gw/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"sync"

networkingv1 "k8s.io/api/networking/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/validation/field"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -55,6 +56,9 @@ type ProviderConf struct {
type Provider interface {
CustomResourceReader
ResourceConverter

// GetCRDs returns the list of CustomResourceDefinitions associated with the Provider.
GetCRDs() []schema.GroupKind
}

type CustomResourceReader interface {
Expand Down
5 changes: 5 additions & 0 deletions pkg/i2gw/providers/apisix/apisix.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"

"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
)

Expand Down Expand Up @@ -73,3 +74,7 @@ func (p *Provider) ReadResourcesFromFile(_ context.Context, filename string) err
p.storage = storage
return nil
}

func (p *Provider) GetCRDs() []schema.GroupKind {
return nil
}
Comment on lines +78 to +80
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar comment below on how we handle, provider == kong but ingress is gce. The implemented approach here would not print the gce ingress (although it hasn't been converted)

8 changes: 4 additions & 4 deletions pkg/i2gw/providers/apisix/resource_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ package apisix
import (
"context"

"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw"
"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw/providers/common"
"k8s.io/apimachinery/pkg/util/sets"

"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw"
)

// converter implements the i2gw.CustomResourceReader interface.
Expand All @@ -40,7 +40,7 @@ func (r *resourceReader) readResourcesFromCluster(ctx context.Context) (*storage
// read apisix related resources from cluster.
storage := newResourcesStorage()

ingresses, err := common.ReadIngressesFromCluster(ctx, r.conf.Client, sets.New(ApisixIngressClass))
ingresses, err := i2gw.ReadIngressesFromCluster(ctx, r.conf.Client, sets.New(ApisixIngressClass))
if err != nil {
return nil, err
}
Expand All @@ -52,7 +52,7 @@ func (r *resourceReader) readResourcesFromFile(filename string) (*storage, error
// read apisix related resources from file.
storage := newResourcesStorage()

ingresses, err := common.ReadIngressesFromFile(filename, r.conf.Namespace, sets.New[string](ApisixIngressClass))
ingresses, err := i2gw.ReadIngressesFromFile(filename, r.conf.Namespace, sets.New[string](ApisixIngressClass))
if err != nil {
return nil, err
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/i2gw/providers/common/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
networkingv1beta1 "k8s.io/api/networking/v1beta1"
"k8s.io/apimachinery/pkg/util/validation/field"
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"

"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw"
)

func GetIngressClass(ingress networkingv1.Ingress) string {
Expand Down Expand Up @@ -58,7 +60,7 @@ func GetRuleGroups(ingresses []networkingv1.Ingress) map[string]IngressRuleGroup
ruleGroups := make(map[string]IngressRuleGroup)

for _, ingress := range ingresses {
ingressClass := GetIngressClass(ingress)
ingressClass := i2gw.GetIngressClass(ingress)

for _, rule := range ingress.Spec.Rules {

Expand Down
5 changes: 5 additions & 0 deletions pkg/i2gw/providers/gce/gce.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"

"github.com/kubernetes-sigs/ingress2gateway/pkg/i2gw"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
)

Expand Down Expand Up @@ -69,3 +70,7 @@ func (p *Provider) ReadResourcesFromFile(_ context.Context, filename string) err
func (p *Provider) ToGatewayAPI() (i2gw.GatewayResources, field.ErrorList) {
return p.converter.convert(p.storage)
}

func (p *Provider) GetCRDs() []schema.GroupKind {
return nil
}
Loading
Loading