2020-12-15 15:40:05 +00:00
|
|
|
package gateway
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2021-03-04 19:08:03 +00:00
|
|
|
"os"
|
2020-12-15 15:40:05 +00:00
|
|
|
"path/filepath"
|
|
|
|
|
2023-02-03 14:24:05 +00:00
|
|
|
"github.com/traefik/traefik/v3/pkg/provider/kubernetes/k8s"
|
2020-12-15 15:40:05 +00:00
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/labels"
|
2023-04-17 08:56:36 +00:00
|
|
|
kscheme "k8s.io/client-go/kubernetes/scheme"
|
|
|
|
gatev1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
|
2020-12-15 15:40:05 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var _ Client = (*clientMock)(nil)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
// required by k8s.MustParseYaml
|
2023-04-17 08:56:36 +00:00
|
|
|
err := gatev1alpha2.AddToScheme(kscheme.Scheme)
|
2020-12-15 15:40:05 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type clientMock struct {
|
2021-10-04 13:46:08 +00:00
|
|
|
services []*corev1.Service
|
|
|
|
secrets []*corev1.Secret
|
|
|
|
endpoints []*corev1.Endpoints
|
|
|
|
namespaces []*corev1.Namespace
|
2020-12-15 15:40:05 +00:00
|
|
|
|
|
|
|
apiServiceError error
|
|
|
|
apiSecretError error
|
|
|
|
apiEndpointsError error
|
|
|
|
|
2023-04-17 08:56:36 +00:00
|
|
|
gatewayClasses []*gatev1alpha2.GatewayClass
|
|
|
|
gateways []*gatev1alpha2.Gateway
|
|
|
|
httpRoutes []*gatev1alpha2.HTTPRoute
|
|
|
|
tcpRoutes []*gatev1alpha2.TCPRoute
|
|
|
|
tlsRoutes []*gatev1alpha2.TLSRoute
|
2020-12-15 15:40:05 +00:00
|
|
|
|
|
|
|
watchChan chan interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newClientMock(paths ...string) clientMock {
|
|
|
|
var c clientMock
|
|
|
|
|
|
|
|
for _, path := range paths {
|
2021-03-04 19:08:03 +00:00
|
|
|
yamlContent, err := os.ReadFile(filepath.FromSlash("./fixtures/" + path))
|
2020-12-15 15:40:05 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
k8sObjects := k8s.MustParseYaml(yamlContent)
|
|
|
|
for _, obj := range k8sObjects {
|
|
|
|
switch o := obj.(type) {
|
|
|
|
case *corev1.Service:
|
|
|
|
c.services = append(c.services, o)
|
|
|
|
case *corev1.Secret:
|
|
|
|
c.secrets = append(c.secrets, o)
|
2021-10-04 13:46:08 +00:00
|
|
|
case *corev1.Namespace:
|
|
|
|
c.namespaces = append(c.namespaces, o)
|
2020-12-15 15:40:05 +00:00
|
|
|
case *corev1.Endpoints:
|
|
|
|
c.endpoints = append(c.endpoints, o)
|
2023-04-17 08:56:36 +00:00
|
|
|
case *gatev1alpha2.GatewayClass:
|
2020-12-15 15:40:05 +00:00
|
|
|
c.gatewayClasses = append(c.gatewayClasses, o)
|
2023-04-17 08:56:36 +00:00
|
|
|
case *gatev1alpha2.Gateway:
|
2020-12-15 15:40:05 +00:00
|
|
|
c.gateways = append(c.gateways, o)
|
2023-04-17 08:56:36 +00:00
|
|
|
case *gatev1alpha2.HTTPRoute:
|
2020-12-15 15:40:05 +00:00
|
|
|
c.httpRoutes = append(c.httpRoutes, o)
|
2023-04-17 08:56:36 +00:00
|
|
|
case *gatev1alpha2.TCPRoute:
|
2021-05-20 09:50:12 +00:00
|
|
|
c.tcpRoutes = append(c.tcpRoutes, o)
|
2023-04-17 08:56:36 +00:00
|
|
|
case *gatev1alpha2.TLSRoute:
|
2021-05-20 09:50:12 +00:00
|
|
|
c.tlsRoutes = append(c.tlsRoutes, o)
|
2020-12-15 15:40:05 +00:00
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("Unknown runtime object %+v %T", o, o))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2023-04-17 08:56:36 +00:00
|
|
|
func (c clientMock) UpdateGatewayStatus(gateway *gatev1alpha2.Gateway, gatewayStatus gatev1alpha2.GatewayStatus) error {
|
2020-12-15 15:40:05 +00:00
|
|
|
for _, g := range c.gateways {
|
|
|
|
if g.Name == gateway.Name {
|
|
|
|
if !statusEquals(g.Status, gatewayStatus) {
|
|
|
|
g.Status = gatewayStatus
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return fmt.Errorf("cannot update gateway %v", gateway.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-04-17 08:56:36 +00:00
|
|
|
func (c clientMock) UpdateGatewayClassStatus(gatewayClass *gatev1alpha2.GatewayClass, condition metav1.Condition) error {
|
2020-12-15 15:40:05 +00:00
|
|
|
for _, gc := range c.gatewayClasses {
|
|
|
|
if gc.Name == gatewayClass.Name {
|
|
|
|
for _, c := range gc.Status.Conditions {
|
|
|
|
if c.Type == condition.Type && c.Status != condition.Status {
|
|
|
|
c.Status = condition.Status
|
|
|
|
c.LastTransitionTime = condition.LastTransitionTime
|
|
|
|
c.Message = condition.Message
|
|
|
|
c.Reason = condition.Reason
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-04-17 08:56:36 +00:00
|
|
|
func (c clientMock) UpdateGatewayStatusConditions(gateway *gatev1alpha2.Gateway, condition metav1.Condition) error {
|
2020-12-15 15:40:05 +00:00
|
|
|
for _, g := range c.gatewayClasses {
|
|
|
|
if g.Name == gateway.Name {
|
|
|
|
for _, c := range g.Status.Conditions {
|
|
|
|
if c.Type == condition.Type && (c.Status != condition.Status || c.Reason != condition.Reason) {
|
|
|
|
c.Status = condition.Status
|
|
|
|
c.LastTransitionTime = condition.LastTransitionTime
|
|
|
|
c.Message = condition.Message
|
|
|
|
c.Reason = condition.Reason
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-04-17 08:56:36 +00:00
|
|
|
func (c clientMock) GetGatewayClasses() ([]*gatev1alpha2.GatewayClass, error) {
|
2020-12-15 15:40:05 +00:00
|
|
|
return c.gatewayClasses, nil
|
|
|
|
}
|
|
|
|
|
2023-04-17 08:56:36 +00:00
|
|
|
func (c clientMock) GetGateways() []*gatev1alpha2.Gateway {
|
2020-12-15 15:40:05 +00:00
|
|
|
return c.gateways
|
|
|
|
}
|
|
|
|
|
2021-10-04 13:46:08 +00:00
|
|
|
func inNamespace(m metav1.ObjectMeta, s string) bool {
|
|
|
|
return s == metav1.NamespaceAll || m.Namespace == s
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c clientMock) GetNamespaces(selector labels.Selector) ([]string, error) {
|
|
|
|
var ns []string
|
|
|
|
for _, namespace := range c.namespaces {
|
|
|
|
if selector.Matches(labels.Set(namespace.Labels)) {
|
|
|
|
ns = append(ns, namespace.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ns, nil
|
|
|
|
}
|
2020-12-15 15:40:05 +00:00
|
|
|
|
2023-04-17 08:56:36 +00:00
|
|
|
func (c clientMock) GetHTTPRoutes(namespaces []string) ([]*gatev1alpha2.HTTPRoute, error) {
|
|
|
|
var httpRoutes []*gatev1alpha2.HTTPRoute
|
2021-10-04 13:46:08 +00:00
|
|
|
for _, namespace := range namespaces {
|
|
|
|
for _, httpRoute := range c.httpRoutes {
|
2021-11-09 10:34:06 +00:00
|
|
|
if inNamespace(httpRoute.ObjectMeta, namespace) {
|
2021-10-04 13:46:08 +00:00
|
|
|
httpRoutes = append(httpRoutes, httpRoute)
|
|
|
|
}
|
2020-12-15 15:40:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return httpRoutes, nil
|
|
|
|
}
|
|
|
|
|
2023-04-17 08:56:36 +00:00
|
|
|
func (c clientMock) GetTCPRoutes(namespaces []string) ([]*gatev1alpha2.TCPRoute, error) {
|
|
|
|
var tcpRoutes []*gatev1alpha2.TCPRoute
|
2021-10-04 13:46:08 +00:00
|
|
|
for _, namespace := range namespaces {
|
|
|
|
for _, tcpRoute := range c.tcpRoutes {
|
2021-11-09 10:34:06 +00:00
|
|
|
if inNamespace(tcpRoute.ObjectMeta, namespace) {
|
2021-10-04 13:46:08 +00:00
|
|
|
tcpRoutes = append(tcpRoutes, tcpRoute)
|
|
|
|
}
|
2021-05-20 09:50:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return tcpRoutes, nil
|
|
|
|
}
|
|
|
|
|
2023-04-17 08:56:36 +00:00
|
|
|
func (c clientMock) GetTLSRoutes(namespaces []string) ([]*gatev1alpha2.TLSRoute, error) {
|
|
|
|
var tlsRoutes []*gatev1alpha2.TLSRoute
|
2021-10-04 13:46:08 +00:00
|
|
|
for _, namespace := range namespaces {
|
|
|
|
for _, tlsRoute := range c.tlsRoutes {
|
2021-11-09 10:34:06 +00:00
|
|
|
if inNamespace(tlsRoute.ObjectMeta, namespace) {
|
2021-10-04 13:46:08 +00:00
|
|
|
tlsRoutes = append(tlsRoutes, tlsRoute)
|
|
|
|
}
|
2021-05-20 09:50:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return tlsRoutes, nil
|
|
|
|
}
|
|
|
|
|
2020-12-15 15:40:05 +00:00
|
|
|
func (c clientMock) GetService(namespace, name string) (*corev1.Service, bool, error) {
|
|
|
|
if c.apiServiceError != nil {
|
|
|
|
return nil, false, c.apiServiceError
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, service := range c.services {
|
2021-10-04 13:46:08 +00:00
|
|
|
if inNamespace(service.ObjectMeta, namespace) && service.Name == name {
|
2020-12-15 15:40:05 +00:00
|
|
|
return service, true, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, false, c.apiServiceError
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c clientMock) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) {
|
|
|
|
if c.apiEndpointsError != nil {
|
|
|
|
return nil, false, c.apiEndpointsError
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, endpoints := range c.endpoints {
|
2021-10-04 13:46:08 +00:00
|
|
|
if inNamespace(endpoints.ObjectMeta, namespace) && endpoints.Name == name {
|
2020-12-15 15:40:05 +00:00
|
|
|
return endpoints, true, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &corev1.Endpoints{}, false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c clientMock) GetSecret(namespace, name string) (*corev1.Secret, bool, error) {
|
|
|
|
if c.apiSecretError != nil {
|
|
|
|
return nil, false, c.apiSecretError
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, secret := range c.secrets {
|
2021-10-04 13:46:08 +00:00
|
|
|
if inNamespace(secret.ObjectMeta, namespace) && secret.Name == name {
|
2020-12-15 15:40:05 +00:00
|
|
|
return secret, true, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c clientMock) WatchAll(namespaces []string, stopCh <-chan struct{}) (<-chan interface{}, error) {
|
|
|
|
return c.watchChan, nil
|
|
|
|
}
|