Skip to content

Commit

Permalink
refactor: common missing dependency errors
Browse files Browse the repository at this point in the history
Signed-off-by: KevFan <[email protected]>
  • Loading branch information
KevFan committed Nov 15, 2024
1 parent 5aedad3 commit 90b4385
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 33 deletions.
10 changes: 8 additions & 2 deletions controllers/auth_policies_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

type AuthPolicyValidator struct {
isGatewayAPIInstalled bool
isGatewayProviderInstalled bool
isAuthorinoOperatorInstalled bool
}

Expand Down Expand Up @@ -45,12 +46,17 @@ func (r *AuthPolicyValidator) Validate(ctx context.Context, _ []controller.Resou

state.Store(StateAuthPolicyValid, lo.SliceToMap(policies, func(policy machinery.Policy) (string, error) {
if !r.isGatewayAPIInstalled {
return policy.GetLocator(), kuadrant.NewErrDependencyNotInstalled("Gateway API")
return policy.GetLocator(), kuadrant.MissingGatewayAPIError()
}

if !r.isGatewayProviderInstalled {
return policy.GetLocator(), kuadrant.MissingGatewayProviderError()
}

if !r.isAuthorinoOperatorInstalled {
return policy.GetLocator(), kuadrant.NewErrDependencyNotInstalled("Authorino Operator")
return policy.GetLocator(), kuadrant.MissingAuthorinoOperatorError()
}

var err error
if len(policy.GetTargetRefs()) > 0 && len(topology.Targetables().Children(policy)) == 0 {
ref := policy.GetTargetRefs()[0]
Expand Down
5 changes: 3 additions & 2 deletions controllers/data_plane_policies_workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ var (
//+kubebuilder:rbac:groups=kuadrant.io,resources=ratelimitpolicies/finalizers,verbs=update

func NewDataPlanePoliciesWorkflow(client *dynamic.DynamicClient, isGatewayAPInstalled, isIstioInstalled, isEnvoyGatewayInstalled, isLimitadorOperatorInstalled, isAuthorinoOperatorInstalled bool) *controller.Workflow {
isGatewayProviderInstalled := isIstioInstalled || isEnvoyGatewayInstalled
dataPlanePoliciesValidation := &controller.Workflow{
Tasks: []controller.ReconcileFunc{
(&AuthPolicyValidator{isGatewayAPIInstalled: isGatewayAPInstalled, isAuthorinoOperatorInstalled: isAuthorinoOperatorInstalled}).Subscription().Reconcile,
(&RateLimitPolicyValidator{isGatewayAPIInstalled: isGatewayAPInstalled, isLimitadorOperatorInstalled: isLimitadorOperatorInstalled}).Subscription().Reconcile,
(&AuthPolicyValidator{isGatewayAPIInstalled: isGatewayAPInstalled, isAuthorinoOperatorInstalled: isAuthorinoOperatorInstalled, isGatewayProviderInstalled: isGatewayProviderInstalled}).Subscription().Reconcile,
(&RateLimitPolicyValidator{isGatewayAPIInstalled: isGatewayAPInstalled, isLimitadorOperatorInstalled: isLimitadorOperatorInstalled, isGatewayProviderInstalled: isGatewayProviderInstalled}).Subscription().Reconcile,
},
}

Expand Down
4 changes: 2 additions & 2 deletions controllers/dnspolicies_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ func (r *DNSPoliciesValidator) validate(ctx context.Context, _ []controller.Reso

state.Store(StateDNSPolicyAcceptedKey, lo.SliceToMap(policies, func(p machinery.Policy) (string, error) {
if !r.isGatewayAPIInstalled {
return p.GetLocator(), kuadrant.NewErrDependencyNotInstalled("Gateway API")
return p.GetLocator(), kuadrant.MissingGatewayAPIError()
}

if !r.isDNSOperatorInstalled {
return p.GetLocator(), kuadrant.NewErrDependencyNotInstalled("DNS Operator")
return p.GetLocator(), kuadrant.MissingDNSOperatorError()
}

policy := p.(*kuadrantv1.DNSPolicy)
Expand Down
33 changes: 22 additions & 11 deletions controllers/kuadrant_status_updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const (
type KuadrantStatusUpdater struct {
Client *dynamic.DynamicClient
isGatwayAPIInstalled bool
HasGateway bool
isGatewayProviderInstalled bool
isLimitadorOperatorInstalled bool
isAuthorinoOperatorInstalled bool
}
Expand All @@ -38,7 +38,7 @@ func NewKuadrantStatusUpdater(client *dynamic.DynamicClient, isGatewayAPIInstall
return &KuadrantStatusUpdater{
Client: client,
isGatwayAPIInstalled: isGatewayAPIInstalled,
HasGateway: isGatewayProviderInstalled,
isGatewayProviderInstalled: isGatewayProviderInstalled,
isLimitadorOperatorInstalled: isLimitadorOperatorInstalled,
isAuthorinoOperatorInstalled: isAuthorinoOperatorInstalled,
}
Expand Down Expand Up @@ -129,23 +129,34 @@ func (r *KuadrantStatusUpdater) readyCondition(topology *machinery.Topology, log
}

if !r.isGatwayAPIInstalled {
err := kuadrant.MissingGatewayAPIError()
cond.Status = metav1.ConditionFalse
cond.Reason = "GatewayAPI"
cond.Message = kuadrant.NewErrDependencyNotInstalled("Gateway API").Error()
cond.Reason = string(err.Reason())
cond.Message = err.Error()
return cond
}

if !r.HasGateway {
if !r.isGatewayProviderInstalled {
err := kuadrant.MissingGatewayProviderError()
cond.Status = metav1.ConditionFalse
cond.Reason = "GatewayAPIProviderNotFound"
cond.Message = kuadrant.NewErrDependencyNotInstalled("GatewayAPI provider").Error()
cond.Reason = string(err.Reason())
cond.Message = err.Error()
return cond
}

if !r.isLimitadorOperatorInstalled {
err := kuadrant.MissingLimitadorOperatorError()
cond.Status = metav1.ConditionFalse
cond.Reason = "LimitadorAPIProviderNotFound"
cond.Message = kuadrant.NewErrDependencyNotInstalled("Limitador Operator").Error()
cond.Reason = string(err.Reason())
cond.Message = err.Error()
return cond
}

if !r.isAuthorinoOperatorInstalled {
err := kuadrant.MissingAuthorinoOperatorError()
cond.Status = metav1.ConditionFalse
cond.Reason = string(err.Reason())
cond.Message = err.Error()
return cond
}

Expand Down Expand Up @@ -173,7 +184,7 @@ func checkLimitadorReady(topology *machinery.Topology, logger logr.Logger) *stri
return ptr.To("limitador resoure not in topology")
}

statusConditionReady := meta.FindStatusCondition(limitadorObj.Status.Conditions, "Ready")
statusConditionReady := meta.FindStatusCondition(limitadorObj.Status.Conditions, limitadorv1alpha1.StatusConditionReady)
if statusConditionReady == nil {
return ptr.To("Ready condition not found")
}
Expand All @@ -191,7 +202,7 @@ func checkAuthorinoAvailable(topology *machinery.Topology, logger logr.Logger) *
return ptr.To("authorino resoure not in topology")
}

readyCondition := authorino.FindAuthorinoStatusCondition(authorinoObj.Status.Conditions, limitadorv1alpha1.StatusConditionReady)
readyCondition := authorino.FindAuthorinoStatusCondition(authorinoObj.Status.Conditions, "Ready")
if readyCondition == nil {
return ptr.To("Ready condition not found")
}
Expand Down
9 changes: 7 additions & 2 deletions controllers/ratelimit_policies_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
type RateLimitPolicyValidator struct {
isLimitadorOperatorInstalled bool
isGatewayAPIInstalled bool
isGatewayProviderInstalled bool
}

// RateLimitPolicyValidator subscribes to events with potential to flip the validity of rate limit policies
Expand Down Expand Up @@ -45,11 +46,15 @@ func (r *RateLimitPolicyValidator) Validate(ctx context.Context, _ []controller.

state.Store(StateRateLimitPolicyValid, lo.SliceToMap(policies, func(policy machinery.Policy) (string, error) {
if !r.isGatewayAPIInstalled {
return policy.GetLocator(), kuadrant.NewErrDependencyNotInstalled("Gateway API")
return policy.GetLocator(), kuadrant.MissingGatewayAPIError()
}

if !r.isGatewayProviderInstalled {
return policy.GetLocator(), kuadrant.MissingGatewayProviderError()
}

if !r.isLimitadorOperatorInstalled {
return policy.GetLocator(), kuadrant.NewErrDependencyNotInstalled("Limitador Operator")
return policy.GetLocator(), kuadrant.MissingLimitadorOperatorError()
}

var err error
Expand Down
4 changes: 2 additions & 2 deletions controllers/tlspolicies_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ func (t *TLSPoliciesValidator) Validate(ctx context.Context, _ []controller.Reso

state.Store(TLSPolicyAcceptedKey, lo.SliceToMap(policies, func(p machinery.Policy) (string, error) {
if !t.isGatewayAPIInstalled {
return p.GetLocator(), kuadrant.NewErrDependencyNotInstalled("Gateway API")
return p.GetLocator(), kuadrant.MissingGatewayAPIError()
}

if !t.isCertManagerInstalled {
return p.GetLocator(), kuadrant.NewErrDependencyNotInstalled("Cert Manager")
return p.GetLocator(), kuadrant.MissingCertManagerError()
}

policy := p.(*kuadrantv1.TLSPolicy)
Expand Down
26 changes: 26 additions & 0 deletions pkg/kuadrant/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,29 @@ func (e ErrSystemResource) Error() string {
func (e ErrSystemResource) Reason() gatewayapiv1alpha2.PolicyConditionReason {
return PolicyReasonMissingResource
}

// Common ErrDependencyNotInstalled errors

func MissingGatewayAPIError() PolicyError {
return NewErrDependencyNotInstalled("Gateway API")
}

func MissingGatewayProviderError() PolicyError {
return NewErrDependencyNotInstalled("Gateway API provider (istio / envoy gateway)")
}

func MissingAuthorinoOperatorError() PolicyError {
return NewErrDependencyNotInstalled("Authorino Operator")
}

func MissingLimitadorOperatorError() PolicyError {
return NewErrDependencyNotInstalled("Limitador Operator")
}

func MissingDNSOperatorError() PolicyError {
return NewErrDependencyNotInstalled("DNS Operator")
}

func MissingCertManagerError() PolicyError {
return NewErrDependencyNotInstalled("Cert Manager")
}
2 changes: 1 addition & 1 deletion tests/bare_k8s/kuadrant_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ var _ = Describe("Kuadrant controller is disabled", func() {
cond := meta.FindStatusCondition(kuadrantCR.Status.Conditions, controllers.ReadyConditionType)
g.Expect(cond).ToNot(BeNil())
g.Expect(cond.Status).To(Equal(metav1.ConditionFalse))
g.Expect(cond.Reason).To(Equal("GatewayAPI"))
g.Expect(cond.Reason).To(Equal("MissingDependency"))
g.Expect(cond.Message).To(Equal("Gateway API is not installed, please restart pod once dependency has been installed"))
}).WithContext(ctx).Should(Succeed())
}, testTimeOut)
Expand Down
89 changes: 78 additions & 11 deletions tests/gatewayapi/kuadrant_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import (
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1"
gatewayapiv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"

kuadrantv1 "github.com/kuadrant/kuadrant-operator/api/v1"
kuadrantv1beta1 "github.com/kuadrant/kuadrant-operator/api/v1beta1"
"github.com/kuadrant/kuadrant-operator/controllers"
"github.com/kuadrant/kuadrant-operator/tests"
Expand All @@ -19,8 +22,8 @@ import (
var _ = Describe("Kuadrant controller when gateway provider is missing", func() {
var (
testNamespace string
kuadrantName string = "local"
afterEachTimeOut = NodeTimeout(3 * time.Minute)
testTimeOut = SpecTimeout(15 * time.Second)
afterEachTimeOut = NodeTimeout(3 * time.Minute)
)

BeforeEach(func(ctx SpecContext) {
Expand All @@ -32,29 +35,93 @@ var _ = Describe("Kuadrant controller when gateway provider is missing", func()
}, afterEachTimeOut)

Context("when default kuadrant CR is created", func() {
It("Status reports error", func(ctx SpecContext) {
It("Status reports missing Gateway API provider (istio / envoy gateway)", func(ctx SpecContext) {
kuadrantCR := &kuadrantv1beta1.Kuadrant{
TypeMeta: metav1.TypeMeta{
Kind: "Kuadrant",
APIVersion: kuadrantv1beta1.GroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: kuadrantName,
Name: "local",
Namespace: testNamespace,
},
}
Expect(testClient().Create(ctx, kuadrantCR)).ToNot(HaveOccurred())

Eventually(func(g Gomega) {
kObj := &kuadrantv1beta1.Kuadrant{}
err := testClient().Get(ctx, client.ObjectKeyFromObject(kuadrantCR), kObj)
g.Expect(testClient().Get(ctx, client.ObjectKeyFromObject(kuadrantCR), kuadrantCR)).ToNot(HaveOccurred())
cond := meta.FindStatusCondition(kuadrantCR.Status.Conditions, controllers.ReadyConditionType)
g.Expect(cond).ToNot(BeNil())
g.Expect(cond.Status).To(Equal(metav1.ConditionFalse))
g.Expect(cond.Reason).To(Equal("MissingDependency"))
g.Expect(cond.Message).To(Equal("Gateway API provider (istio / envoy gateway) is not installed, please restart pod once dependency has been installed"))
}).WithContext(ctx).Should(Succeed())
}, testTimeOut)
})

Context("when rate limit policy is created", func() {
It("Status is populated with missing Gateway API provider (istio / envoy gateway)", func(ctx SpecContext) {
policy := &kuadrantv1.RateLimitPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "rlp",
Namespace: testNamespace,
},
Spec: kuadrantv1.RateLimitPolicySpec{
TargetRef: gatewayapiv1alpha2.LocalPolicyTargetReferenceWithSectionName{
LocalPolicyTargetReference: gatewayapiv1alpha2.LocalPolicyTargetReference{
Kind: "Gateway",
Group: gatewayapiv1.GroupName,
Name: "test",
},
},
},
}

Expect(testClient().Create(ctx, policy)).To(Succeed())

Eventually(func(g Gomega) {
err := testClient().Get(ctx, client.ObjectKeyFromObject(policy), policy)
g.Expect(err).ToNot(HaveOccurred())
cond := meta.FindStatusCondition(kObj.Status.Conditions, string(controllers.ReadyConditionType))

cond := meta.FindStatusCondition(policy.Status.Conditions, string(gatewayapiv1alpha2.PolicyConditionAccepted))
g.Expect(cond).ToNot(BeNil())
g.Expect(cond.Status).To(Equal(metav1.ConditionFalse))
g.Expect(cond.Reason).To(Equal("MissingDependency"))
g.Expect(cond.Message).To(Equal("Gateway API provider (istio / envoy gateway) is not installed, please restart pod once dependency has been installed"))
}).WithContext(ctx).Should(Succeed())
}, testTimeOut)
})

Context("when auth policy is created", func() {
It("Status is populated with missing Gateway API provider (istio / envoy gateway)", func(ctx SpecContext) {
policy := &kuadrantv1.AuthPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "auth",
Namespace: testNamespace,
},
Spec: kuadrantv1.AuthPolicySpec{
TargetRef: gatewayapiv1alpha2.LocalPolicyTargetReferenceWithSectionName{
LocalPolicyTargetReference: gatewayapiv1alpha2.LocalPolicyTargetReference{
Kind: "Gateway",
Group: gatewayapiv1.GroupName,
Name: "test",
},
},
},
}

Expect(testClient().Create(ctx, policy)).To(Succeed())

Eventually(func(g Gomega) {
err := testClient().Get(ctx, client.ObjectKeyFromObject(policy), policy)
g.Expect(err).ToNot(HaveOccurred())

cond := meta.FindStatusCondition(policy.Status.Conditions, string(gatewayapiv1alpha2.PolicyConditionAccepted))
g.Expect(cond).ToNot(BeNil())
g.Expect(cond.Status).To(Equal(metav1.ConditionFalse))
g.Expect(cond.Reason).To(Equal("GatewayAPIProviderNotFound"))
g.Expect(cond.Message).To(Equal("GatewayAPI provider is not installed, please restart pod once dependency has been installed"))
}, time.Minute, 15*time.Second).WithContext(ctx).Should(Succeed())
})
g.Expect(cond.Reason).To(Equal("MissingDependency"))
g.Expect(cond.Message).To(Equal("Gateway API provider (istio / envoy gateway) is not installed, please restart pod once dependency has been installed"))
}).WithContext(ctx).Should(Succeed())
}, testTimeOut)
})
})

0 comments on commit 90b4385

Please sign in to comment.