Skip to content

Commit

Permalink
chore: Refactor 'VirtualService' creation
Browse files Browse the repository at this point in the history
  • Loading branch information
c-pius committed Feb 23, 2024
1 parent fbd5bd8 commit 380822d
Show file tree
Hide file tree
Showing 9 changed files with 414 additions and 110 deletions.
2 changes: 1 addition & 1 deletion internal/controller/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

"github.com/kyma-project/lifecycle-manager/api/shared"
"github.com/kyma-project/lifecycle-manager/api/v1beta2"
"github.com/kyma-project/lifecycle-manager/pkg/istio"
"github.com/kyma-project/lifecycle-manager/internal/istio"
"github.com/kyma-project/lifecycle-manager/pkg/security"
"github.com/kyma-project/lifecycle-manager/pkg/watch"
)
Expand Down
10 changes: 8 additions & 2 deletions internal/controller/watcher_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ import (

"github.com/kyma-project/lifecycle-manager/api/shared"
"github.com/kyma-project/lifecycle-manager/api/v1beta2"
"github.com/kyma-project/lifecycle-manager/pkg/istio"
"github.com/kyma-project/lifecycle-manager/internal/istio"
"github.com/kyma-project/lifecycle-manager/internal/istio/resource"
"github.com/kyma-project/lifecycle-manager/pkg/log"
"github.com/kyma-project/lifecycle-manager/pkg/queue"
"github.com/kyma-project/lifecycle-manager/pkg/status"
Expand Down Expand Up @@ -144,7 +145,12 @@ func (r *WatcherReconciler) handleDeletingState(ctx context.Context, watcherCR *
func (r *WatcherReconciler) handleProcessingState(ctx context.Context,
watcherCR *v1beta2.Watcher,
) (ctrl.Result, error) {
virtualSvc, err := r.IstioClient.NewVirtualService(ctx, watcherCR, r.WatcherVSNamespace)
gateways, err := r.IstioClient.LookupGateways(ctx, watcherCR)
if err != nil {
return r.updateWatcherState(ctx, watcherCR, shared.StateError, err)
}

virtualSvc, err := resource.NewVirtualService(r.WatcherVSNamespace, watcherCR, gateways)
if err != nil {
return r.updateWatcherState(ctx, watcherCR, shared.StateError, err)
}
Expand Down
105 changes: 1 addition & 104 deletions pkg/istio/client.go → internal/istio/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,9 @@ import (

const (
firstElementIdx = 0
contractVersion = "v1"
prefixFormat = "/%s/%s/event"
)

var (
ErrCantFindMatchingGateway = errors.New("can't find matching Istio Gateway")
ErrCantFindGatewayServersHost = errors.New("can't find Istio Gateway servers hosts")
)
var ErrCantFindMatchingGateway = errors.New("can't find matching Istio Gateway")

type Client struct {
istioclient.Interface
Expand Down Expand Up @@ -68,34 +63,6 @@ func (c *Client) ListVirtualServices(ctx context.Context, namespace string) (*is
return virtualServiceList, nil
}

func (c *Client) NewVirtualService(ctx context.Context, watcher *v1beta2.Watcher, targetNamespace string,
) (*istioclientapiv1beta1.VirtualService, error) {
if watcher == nil {
return &istioclientapiv1beta1.VirtualService{}, nil
}

virtualSvc := &istioclientapiv1beta1.VirtualService{}
virtualSvc.SetName(watcher.Name)
virtualSvc.SetNamespace(targetNamespace)

gateways, err := c.LookupGateways(ctx, watcher)
if err != nil {
return nil, err
}

addGateways(gateways, virtualSvc)

if err := addHosts(gateways, virtualSvc); err != nil {
return nil, err
}

virtualSvc.Spec.Http = []*istioapiv1beta1.HTTPRoute{
PrepareIstioHTTPRouteForCR(watcher),
}

return virtualSvc, nil
}

func (c *Client) CreateVirtualService(ctx context.Context, virtualSvc *istioclientapiv1beta1.VirtualService) error {
_, err := c.NetworkingV1beta1().
VirtualServices(virtualSvc.GetNamespace()).
Expand All @@ -106,46 +73,6 @@ func (c *Client) CreateVirtualService(ctx context.Context, virtualSvc *istioclie
return nil
}

func addGateways(gateways []*istioclientapiv1beta1.Gateway, virtualSvc *istioclientapiv1beta1.VirtualService) {
gatewayLists := convertToGatewayList(gateways)
virtualSvc.Spec.Gateways = gatewayLists
}

func convertToGatewayList(gateways []*istioclientapiv1beta1.Gateway) []string {
gatewayLists := make([]string, 0)
for i := range gateways {
gatewayLists = append(gatewayLists, client.ObjectKeyFromObject(gateways[i]).String())
}
return gatewayLists
}

func addHosts(gateways []*istioclientapiv1beta1.Gateway, virtualSvc *istioclientapiv1beta1.VirtualService) error {
hosts, err := getHosts(gateways)
if err != nil {
return err
}
virtualSvc.Spec.Hosts = hosts
return nil
}

func getHosts(gateways []*istioclientapiv1beta1.Gateway) ([]string, error) {
hosts := make([]string, 0)

for _, g := range gateways {
servers := g.Spec.GetServers()
if len(servers) == 0 || len(servers[0].GetHosts()) == 0 {
return nil, fmt.Errorf("for gateway %s: %w",
client.ObjectKeyFromObject(g).String(),
ErrCantFindGatewayServersHost)
}
for _, s := range servers {
hosts = append(hosts, s.GetHosts()...)
}
}

return hosts, nil
}

func (c *Client) LookupGateways(ctx context.Context, watcher *v1beta2.Watcher) ([]*istioclientapiv1beta1.Gateway,
error,
) {
Expand Down Expand Up @@ -226,33 +153,3 @@ func IsRouteConfigEqual(route1 *istioapiv1beta1.HTTPRoute, route2 *istioapiv1bet

return true
}

func PrepareIstioHTTPRouteForCR(obj *v1beta2.Watcher) *istioapiv1beta1.HTTPRoute {
return &istioapiv1beta1.HTTPRoute{
Name: client.ObjectKeyFromObject(obj).String(),
Match: []*istioapiv1beta1.HTTPMatchRequest{
{
Uri: &istioapiv1beta1.StringMatch{
MatchType: &istioapiv1beta1.StringMatch_Prefix{
//nolint:nosnakecase // external type
Prefix: fmt.Sprintf(prefixFormat, contractVersion, obj.GetModuleName()),
},
},
},
},
Route: []*istioapiv1beta1.HTTPRouteDestination{
{
Destination: &istioapiv1beta1.Destination{
Host: destinationHost(obj.Spec.ServiceInfo.Name, obj.Spec.ServiceInfo.Namespace),
Port: &istioapiv1beta1.PortSelector{
Number: uint32(obj.Spec.ServiceInfo.Port),
},
},
},
},
}
}

func destinationHost(serviceName, serviceNamespace string) string {
return fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, serviceNamespace)
}
8 changes: 8 additions & 0 deletions internal/istio/resource/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package resource

import "errors"

var (
ErrInvalidArgument = errors.New("invalid argument")
ErrCantFindGatewayServersHost = errors.New("can't find Istio Gateway servers hosts")
)
110 changes: 110 additions & 0 deletions internal/istio/resource/virtualservice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package resource

import (
"errors"
"fmt"

istioapiv1beta1 "istio.io/api/networking/v1beta1"
istioclientapiv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/kyma-project/lifecycle-manager/api/v1beta2"
)

const (
contractVersion = "v1"
prefixFormat = "/%s/%s/event"
)

func NewVirtualService(targetNamespace string, watcher *v1beta2.Watcher, gateways []*istioclientapiv1beta1.Gateway) (*istioclientapiv1beta1.VirtualService, error) {
if targetNamespace == "" {
return nil, fmt.Errorf("%w targetNamespace", ErrInvalidArgument)
}

if watcher == nil {
return nil, fmt.Errorf("%w watcher", ErrInvalidArgument)
}

if watcher.Name == "" {
return nil, fmt.Errorf("%w watcher.Name", ErrInvalidArgument)
}

if len(gateways) == 0 {
return nil, fmt.Errorf("%w gateways", ErrInvalidArgument)
}

hosts, err := getHosts(gateways)
if err != nil {
return nil, errors.Join(ErrInvalidArgument, err)
}

virtualService := &istioclientapiv1beta1.VirtualService{}
virtualService.SetName(watcher.Name)
virtualService.SetNamespace(targetNamespace)
virtualService.Spec.Gateways = getGatewayNames(gateways)
virtualService.Spec.Hosts = hosts
virtualService.Spec.Http = []*istioapiv1beta1.HTTPRoute{
PrepareIstioHTTPRouteForCR(watcher),
}

return virtualService, nil
}

func PrepareIstioHTTPRouteForCR(obj *v1beta2.Watcher) *istioapiv1beta1.HTTPRoute {
return &istioapiv1beta1.HTTPRoute{
Name: client.ObjectKeyFromObject(obj).String(),
Match: []*istioapiv1beta1.HTTPMatchRequest{
{
Uri: &istioapiv1beta1.StringMatch{
MatchType: &istioapiv1beta1.StringMatch_Prefix{
//nolint:nosnakecase // external type
Prefix: fmt.Sprintf(prefixFormat, contractVersion, obj.GetModuleName()),
},
},
},
},
Route: []*istioapiv1beta1.HTTPRouteDestination{
{
Destination: &istioapiv1beta1.Destination{
Host: destinationHost(obj.Spec.ServiceInfo.Name, obj.Spec.ServiceInfo.Namespace),
Port: &istioapiv1beta1.PortSelector{
Number: uint32(obj.Spec.ServiceInfo.Port),
},
},
},
},
}
}

func getGatewayNames(gateways []*istioclientapiv1beta1.Gateway) []string {
gatewayNames := make([]string, 0)
for _, gateway := range gateways {
gatewayNames = append(gatewayNames, client.ObjectKeyFromObject(gateway).String())
}
return gatewayNames
}

func getHosts(gateways []*istioclientapiv1beta1.Gateway) ([]string, error) {
hosts := make([]string, 0)

for _, gateway := range gateways {
gatewayHosts := make([]string, 0)
for _, server := range gateway.Spec.GetServers() {
gatewayHosts = append(gatewayHosts, server.GetHosts()...)
}

if len(gatewayHosts) == 0 {
return nil, fmt.Errorf("for gateway %s: %w",
client.ObjectKeyFromObject(gateway).String(),
ErrCantFindGatewayServersHost)
}

hosts = append(hosts, gatewayHosts...)
}

return hosts, nil
}

func destinationHost(serviceName, serviceNamespace string) string {
return fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, serviceNamespace)
}
Loading

0 comments on commit 380822d

Please sign in to comment.