diff --git a/api/v1alpha1/topology.go b/api/v1alpha1/topology.go index 707f001c1..0ab5156bf 100644 --- a/api/v1alpha1/topology.go +++ b/api/v1alpha1/topology.go @@ -9,9 +9,9 @@ import ( var ( DNSPoliciesResource = GroupVersion.WithResource("dnspolicies") - DNSPolicyKind = schema.GroupKind{Group: GroupVersion.Group, Kind: "DNSPolicy"} + DNSPolicyGroupKind = schema.GroupKind{Group: GroupVersion.Group, Kind: "DNSPolicy"} TLSPoliciesResource = GroupVersion.WithResource("tlspolicies") - TLSPolicyKind = schema.GroupKind{Group: GroupVersion.Group, Kind: "TLSPolicy"} + TLSPolicyGroupKind = schema.GroupKind{Group: GroupVersion.Group, Kind: "TLSPolicy"} ) var _ machinery.Policy = &DNSPolicy{} diff --git a/api/v1beta1/topology.go b/api/v1beta1/topology.go index 65d52c7be..a2cf74945 100644 --- a/api/v1beta1/topology.go +++ b/api/v1beta1/topology.go @@ -11,13 +11,13 @@ import ( ) var ( - AuthorinoKind = schema.GroupKind{Group: authorinov1beta1.GroupVersion.Group, Kind: "Authorino"} - KuadrantKind = schema.GroupKind{Group: GroupVersion.Group, Kind: "Kuadrant"} - LimitadorKind = schema.GroupKind{Group: limitadorv1alpha1.GroupVersion.Group, Kind: "Limitador"} + AuthorinoGroupKind = schema.GroupKind{Group: authorinov1beta1.GroupVersion.Group, Kind: "Authorino"} + KuadrantGroupKind = schema.GroupKind{Group: GroupVersion.Group, Kind: "Kuadrant"} + LimitadorGroupKind = schema.GroupKind{Group: limitadorv1alpha1.GroupVersion.Group, Kind: "Limitador"} - AuthorinoResource = authorinov1beta1.GroupVersion.WithResource("authorinos") - KuadrantResource = GroupVersion.WithResource("kuadrants") - LimitadorResource = limitadorv1alpha1.GroupVersion.WithResource("limitadors") + AuthorinosResource = authorinov1beta1.GroupVersion.WithResource("authorinos") + KuadrantsResource = GroupVersion.WithResource("kuadrants") + LimitadorsResource = limitadorv1alpha1.GroupVersion.WithResource("limitadors") ) var _ machinery.Object = &Kuadrant{} @@ -27,10 +27,10 @@ func (p *Kuadrant) GetLocator() string { } func LinkKuadrantToGatewayClasses(objs controller.Store) machinery.LinkFunc { - kuadrants := lo.Map(objs.FilterByGroupKind(KuadrantKind), controller.ObjectAs[*Kuadrant]) + kuadrants := lo.Map(objs.FilterByGroupKind(KuadrantGroupKind), controller.ObjectAs[*Kuadrant]) return machinery.LinkFunc{ - From: KuadrantKind, + From: KuadrantGroupKind, To: schema.GroupKind{Group: gwapiv1.GroupVersion.Group, Kind: "GatewayClass"}, Func: func(_ machinery.Object) []machinery.Object { parents := make([]machinery.Object, len(kuadrants)) @@ -43,11 +43,11 @@ func LinkKuadrantToGatewayClasses(objs controller.Store) machinery.LinkFunc { } func LinkKuadrantToLimitador(objs controller.Store) machinery.LinkFunc { - kuadrants := lo.Map(objs.FilterByGroupKind(KuadrantKind), controller.ObjectAs[machinery.Object]) + kuadrants := lo.Map(objs.FilterByGroupKind(KuadrantGroupKind), controller.ObjectAs[machinery.Object]) return machinery.LinkFunc{ - From: KuadrantKind, - To: LimitadorKind, + From: KuadrantGroupKind, + To: LimitadorGroupKind, Func: func(child machinery.Object) []machinery.Object { return lo.Filter(kuadrants, func(kuadrant machinery.Object, _ int) bool { return kuadrant.GetNamespace() == child.GetNamespace() && child.GetName() == "limitador" @@ -57,11 +57,11 @@ func LinkKuadrantToLimitador(objs controller.Store) machinery.LinkFunc { } func LinkKuadrantToAuthorino(objs controller.Store) machinery.LinkFunc { - kuadrants := lo.Map(objs.FilterByGroupKind(KuadrantKind), controller.ObjectAs[machinery.Object]) + kuadrants := lo.Map(objs.FilterByGroupKind(KuadrantGroupKind), controller.ObjectAs[machinery.Object]) return machinery.LinkFunc{ - From: KuadrantKind, - To: AuthorinoKind, + From: KuadrantGroupKind, + To: AuthorinoGroupKind, Func: func(child machinery.Object) []machinery.Object { return lo.Filter(kuadrants, func(kuadrant machinery.Object, _ int) bool { return kuadrant.GetNamespace() == child.GetNamespace() && child.GetName() == "authorino" diff --git a/api/v1beta2/topology.go b/api/v1beta2/topology.go index ea622c47b..25b398e29 100644 --- a/api/v1beta2/topology.go +++ b/api/v1beta2/topology.go @@ -9,9 +9,9 @@ import ( var ( AuthPoliciesResource = GroupVersion.WithResource("authpolicies") - AuthPolicyKind = schema.GroupKind{Group: GroupVersion.Group, Kind: "AuthPolicy"} + AuthPolicyGroupKind = schema.GroupKind{Group: GroupVersion.Group, Kind: "AuthPolicy"} RateLimitPoliciesResource = GroupVersion.WithResource("ratelimitpolicies") - RateLimitPolicyKind = schema.GroupKind{Group: GroupVersion.Group, Kind: "RateLimitPolicy"} + RateLimitPolicyGroupKind = schema.GroupKind{Group: GroupVersion.Group, Kind: "RateLimitPolicy"} ) var _ machinery.Policy = &AuthPolicy{} diff --git a/controllers/auth_workflow.go b/controllers/auth_workflow.go new file mode 100644 index 000000000..8eaf5f251 --- /dev/null +++ b/controllers/auth_workflow.go @@ -0,0 +1,7 @@ +package controllers + +import "github.com/kuadrant/policy-machinery/controller" + +func NewAuthWorkflow() *controller.Workflow { + return &controller.Workflow{} +} diff --git a/controllers/authorino_task.go b/controllers/authorino_reconciler.go similarity index 77% rename from controllers/authorino_task.go rename to controllers/authorino_reconciler.go index 0e7c093c9..ca739c8f4 100644 --- a/controllers/authorino_task.go +++ b/controllers/authorino_reconciler.go @@ -17,31 +17,31 @@ import ( "github.com/kuadrant/kuadrant-operator/api/v1beta1" ) -type AuthorinoCrReconciler struct { +type AuthorinoReconciler struct { Client *dynamic.DynamicClient } -func NewAuthorinoCrReconciler(client *dynamic.DynamicClient) *AuthorinoCrReconciler { - return &AuthorinoCrReconciler{Client: client} +func NewAuthorinoReconciler(client *dynamic.DynamicClient) *AuthorinoReconciler { + return &AuthorinoReconciler{Client: client} } -func (r *AuthorinoCrReconciler) Subscription() *controller.Subscription { +func (r *AuthorinoReconciler) Subscription() *controller.Subscription { return &controller.Subscription{ ReconcileFunc: r.Reconcile, Events: []controller.ResourceEventMatcher{ - {Kind: ptr.To(v1beta1.KuadrantKind), EventType: ptr.To(controller.CreateEvent)}, - {Kind: ptr.To(v1beta1.AuthorinoKind), EventType: ptr.To(controller.DeleteEvent)}, + {Kind: ptr.To(v1beta1.KuadrantGroupKind), EventType: ptr.To(controller.CreateEvent)}, + {Kind: ptr.To(v1beta1.AuthorinoGroupKind), EventType: ptr.To(controller.DeleteEvent)}, }, } } -func (r *AuthorinoCrReconciler) Reconcile(ctx context.Context, _ []controller.ResourceEvent, topology *machinery.Topology, _ error, _ *sync.Map) error { - logger := controller.LoggerFromContext(ctx).WithName("AuthorinoCrReconciler") +func (r *AuthorinoReconciler) Reconcile(ctx context.Context, _ []controller.ResourceEvent, topology *machinery.Topology, _ error, _ *sync.Map) error { + logger := controller.LoggerFromContext(ctx).WithName("AuthorinoReconciler") logger.Info("reconciling authorino resource", "status", "started") defer logger.Info("reconciling authorino resource", "status", "completed") kobjs := lo.FilterMap(topology.Objects().Roots(), func(item machinery.Object, _ int) (*v1beta1.Kuadrant, bool) { - if item.GroupVersionKind().Kind == v1beta1.KuadrantKind.Kind { + if item.GroupVersionKind().Kind == v1beta1.KuadrantGroupKind.Kind { return item.(*v1beta1.Kuadrant), true } return nil, false @@ -58,7 +58,7 @@ func (r *AuthorinoCrReconciler) Reconcile(ctx context.Context, _ []controller.Re } aobjs := lo.FilterMap(topology.Objects().Objects().Children(kobj), func(item machinery.Object, _ int) (machinery.Object, bool) { - if item.GroupVersionKind().Kind == v1beta1.AuthorinoKind.Kind { + if item.GroupVersionKind().Kind == v1beta1.AuthorinoGroupKind.Kind { return item, true } return nil, false @@ -109,7 +109,7 @@ func (r *AuthorinoCrReconciler) Reconcile(ctx context.Context, _ []controller.Re logger.Error(err, "failed to destruct authorino", "status", "error") } logger.Info("creating authorino resource", "status", "processing") - _, err = r.Client.Resource(v1beta1.AuthorinoResource).Namespace(authorino.Namespace).Create(ctx, unstructuredAuthorino, metav1.CreateOptions{}) + _, err = r.Client.Resource(v1beta1.AuthorinosResource).Namespace(authorino.Namespace).Create(ctx, unstructuredAuthorino, metav1.CreateOptions{}) if err != nil { if errors.IsAlreadyExists(err) { logger.Info("already created authorino resource", "status", "acceptable") diff --git a/controllers/dns_workflow.go b/controllers/dns_workflow.go new file mode 100644 index 000000000..99787a34c --- /dev/null +++ b/controllers/dns_workflow.go @@ -0,0 +1,7 @@ +package controllers + +import "github.com/kuadrant/policy-machinery/controller" + +func NewDNSWorkflow() *controller.Workflow { + return &controller.Workflow{} +} diff --git a/controllers/envoy_gateway_extensions_janitor.go b/controllers/envoy_gateway_extensions_janitor.go new file mode 100644 index 000000000..b46db3b93 --- /dev/null +++ b/controllers/envoy_gateway_extensions_janitor.go @@ -0,0 +1,18 @@ +package controllers + +import ( + "github.com/kuadrant/policy-machinery/controller" + "k8s.io/client-go/dynamic" +) + +type EnvoyGatewayJanitor struct { + Client *dynamic.DynamicClient +} + +func NewEnvoyGatewayJanitor(client *dynamic.DynamicClient) *EnvoyGatewayJanitor { + return &EnvoyGatewayJanitor{Client: client} +} + +func (r *EnvoyGatewayJanitor) Subscription() *controller.Subscription { + return &controller.Subscription{} +} diff --git a/controllers/event_logger.go b/controllers/event_logger.go new file mode 100644 index 000000000..a4b85e7ad --- /dev/null +++ b/controllers/event_logger.go @@ -0,0 +1,42 @@ +package controllers + +import ( + "context" + "sync" + + "github.com/google/go-cmp/cmp" + "github.com/kuadrant/policy-machinery/controller" + "github.com/kuadrant/policy-machinery/machinery" +) + +type EventLogger struct{} + +func NewEventLogger() *EventLogger { + return &EventLogger{} +} + +func (e *EventLogger) Log(ctx context.Context, resourceEvents []controller.ResourceEvent, _ *machinery.Topology, err error, _ *sync.Map) error { + logger := controller.LoggerFromContext(ctx).WithName("event logger") + for _, event := range resourceEvents { + // log the event + obj := event.OldObject + if obj == nil { + obj = event.NewObject + } + values := []any{ + "type", event.EventType.String(), + "kind", obj.GetObjectKind().GroupVersionKind().Kind, + "namespace", obj.GetNamespace(), + "name", obj.GetName(), + } + if event.EventType == controller.UpdateEvent && logger.V(1).Enabled() { + values = append(values, "diff", cmp.Diff(event.OldObject, event.NewObject)) + } + logger.Info("new event", values...) + if err != nil { + logger.Error(err, "error passed to reconcile") + } + } + + return nil +} diff --git a/controllers/gateway_policy_discoverability_reconciler.go b/controllers/gateway_policy_discoverability_reconciler.go new file mode 100644 index 000000000..4802bcb68 --- /dev/null +++ b/controllers/gateway_policy_discoverability_reconciler.go @@ -0,0 +1,18 @@ +package controllers + +import ( + "github.com/kuadrant/policy-machinery/controller" + "k8s.io/client-go/dynamic" +) + +type GatewayPolicyDiscoverabilityReconciler struct { + Client *dynamic.DynamicClient +} + +func NewGatewayPolicyDiscoverabilityReconciler(client *dynamic.DynamicClient) *GatewayPolicyDiscoverabilityReconciler { + return &GatewayPolicyDiscoverabilityReconciler{Client: client} +} + +func (r *GatewayPolicyDiscoverabilityReconciler) Subscription() *controller.Subscription { + return &controller.Subscription{} +} diff --git a/controllers/httproute_policy_discoverability_reconciler.go b/controllers/httproute_policy_discoverability_reconciler.go new file mode 100644 index 000000000..e1549723a --- /dev/null +++ b/controllers/httproute_policy_discoverability_reconciler.go @@ -0,0 +1,18 @@ +package controllers + +import ( + "github.com/kuadrant/policy-machinery/controller" + "k8s.io/client-go/dynamic" +) + +type HTTPRoutePolicyDiscoverabilityReconciler struct { + Client *dynamic.DynamicClient +} + +func NewHTTPRoutePolicyDiscoverabilityReconciler(client *dynamic.DynamicClient) *HTTPRoutePolicyDiscoverabilityReconciler { + return &HTTPRoutePolicyDiscoverabilityReconciler{Client: client} +} + +func (r *HTTPRoutePolicyDiscoverabilityReconciler) Subscription() *controller.Subscription { + return &controller.Subscription{} +} diff --git a/controllers/istio_extensions_janitor.go b/controllers/istio_extensions_janitor.go new file mode 100644 index 000000000..5145328d8 --- /dev/null +++ b/controllers/istio_extensions_janitor.go @@ -0,0 +1,18 @@ +package controllers + +import ( + "github.com/kuadrant/policy-machinery/controller" + "k8s.io/client-go/dynamic" +) + +type IstioExtensionsJanitor struct { + Client *dynamic.DynamicClient +} + +func NewIstioExtensionsJanitor(client *dynamic.DynamicClient) *IstioExtensionsJanitor { + return &IstioExtensionsJanitor{Client: client} +} + +func (r *IstioExtensionsJanitor) Subscription() *controller.Subscription { + return &controller.Subscription{} +} diff --git a/controllers/limitador_reconciler.go b/controllers/limitador_reconciler.go new file mode 100644 index 000000000..db2bac902 --- /dev/null +++ b/controllers/limitador_reconciler.go @@ -0,0 +1,18 @@ +package controllers + +import ( + "github.com/kuadrant/policy-machinery/controller" + "k8s.io/client-go/dynamic" +) + +type LimitadorReconciler struct { + Client *dynamic.DynamicClient +} + +func NewLimitadorReconciler(client *dynamic.DynamicClient) *LimitadorReconciler { + return &LimitadorReconciler{Client: client} +} + +func (r *LimitadorReconciler) Subscription() *controller.Subscription { + return &controller.Subscription{} +} diff --git a/controllers/ratelimit_workflow.go b/controllers/ratelimit_workflow.go new file mode 100644 index 000000000..eeb4be09b --- /dev/null +++ b/controllers/ratelimit_workflow.go @@ -0,0 +1,7 @@ +package controllers + +import "github.com/kuadrant/policy-machinery/controller" + +func NewRateLimitWorkflow() *controller.Workflow { + return &controller.Workflow{} +} diff --git a/controllers/state_of_the_world.go b/controllers/state_of_the_world.go index 8c7dcd9b2..ddc6c7517 100644 --- a/controllers/state_of_the_world.go +++ b/controllers/state_of_the_world.go @@ -1,24 +1,18 @@ package controllers import ( - "context" "fmt" - "strings" - "sync" certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" egv1alpha1 "github.com/envoyproxy/gateway/api/v1alpha1" "github.com/go-logr/logr" - "github.com/google/go-cmp/cmp" authorinov1beta1 "github.com/kuadrant/authorino-operator/api/v1beta1" limitadorv1alpha1 "github.com/kuadrant/limitador-operator/api/v1alpha1" "github.com/kuadrant/policy-machinery/controller" - "github.com/kuadrant/policy-machinery/machinery" istioclientgoextensionv1alpha1 "istio.io/client-go/pkg/apis/extensions/v1alpha1" istioclientnetworkingv1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3" istioclientgosecurityv1beta1 "istio.io/client-go/pkg/apis/security/v1beta1" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" @@ -47,32 +41,31 @@ func NewPolicyMachineryController(manager ctrlruntime.Manager, client *dynamic.D controller.ManagedBy(manager), controller.WithLogger(logger), controller.WithClient(client), - controller.WithRunnable("kuadrant watcher", controller.Watch(&kuadrantv1beta1.Kuadrant{}, kuadrantv1beta1.KuadrantResource, metav1.NamespaceAll)), + controller.WithRunnable("kuadrant watcher", controller.Watch(&kuadrantv1beta1.Kuadrant{}, kuadrantv1beta1.KuadrantsResource, metav1.NamespaceAll)), controller.WithRunnable("dnspolicy watcher", controller.Watch(&kuadrantv1alpha1.DNSPolicy{}, kuadrantv1alpha1.DNSPoliciesResource, metav1.NamespaceAll)), controller.WithRunnable("tlspolicy watcher", controller.Watch(&kuadrantv1alpha1.TLSPolicy{}, kuadrantv1alpha1.TLSPoliciesResource, metav1.NamespaceAll)), controller.WithRunnable("authpolicy watcher", controller.Watch(&kuadrantv1beta2.AuthPolicy{}, kuadrantv1beta2.AuthPoliciesResource, metav1.NamespaceAll)), controller.WithRunnable("ratelimitpolicy watcher", controller.Watch(&kuadrantv1beta2.RateLimitPolicy{}, kuadrantv1beta2.RateLimitPoliciesResource, metav1.NamespaceAll)), controller.WithRunnable("topology configmap watcher", controller.Watch(&corev1.ConfigMap{}, controller.ConfigMapsResource, operatorNamespace, controller.FilterResourcesByLabel[*corev1.ConfigMap](fmt.Sprintf("%s=true", kuadrant.TopologyLabel)))), - controller.WithRunnable("limitador watcher", controller.Watch(&limitadorv1alpha1.Limitador{}, kuadrantv1beta1.LimitadorResource, metav1.NamespaceAll)), - controller.WithRunnable("authorino watcher", controller.Watch(&authorinov1beta1.Authorino{}, kuadrantv1beta1.AuthorinoResource, metav1.NamespaceAll)), + controller.WithRunnable("limitador watcher", controller.Watch(&limitadorv1alpha1.Limitador{}, kuadrantv1beta1.LimitadorsResource, metav1.NamespaceAll)), + controller.WithRunnable("authorino watcher", controller.Watch(&authorinov1beta1.Authorino{}, kuadrantv1beta1.AuthorinosResource, metav1.NamespaceAll)), controller.WithPolicyKinds( - kuadrantv1alpha1.DNSPolicyKind, - kuadrantv1alpha1.TLSPolicyKind, - kuadrantv1beta2.AuthPolicyKind, - kuadrantv1beta2.RateLimitPolicyKind, + kuadrantv1alpha1.DNSPolicyGroupKind, + kuadrantv1alpha1.TLSPolicyGroupKind, + kuadrantv1beta2.AuthPolicyGroupKind, + kuadrantv1beta2.RateLimitPolicyGroupKind, ), controller.WithObjectKinds( - kuadrantv1beta1.KuadrantKind, + kuadrantv1beta1.KuadrantGroupKind, ConfigMapGroupKind, - kuadrantv1beta1.LimitadorKind, - kuadrantv1beta1.AuthorinoKind, + kuadrantv1beta1.LimitadorGroupKind, + kuadrantv1beta1.AuthorinoGroupKind, ), controller.WithObjectLinks( kuadrantv1beta1.LinkKuadrantToGatewayClasses, kuadrantv1beta1.LinkKuadrantToLimitador, kuadrantv1beta1.LinkKuadrantToAuthorino, ), - controller.WithReconcile(buildReconciler(client)), } ok, err := kuadrantgatewayapi.IsGatewayAPIInstalled(manager.GetRESTMapper()) @@ -86,8 +79,8 @@ func NewPolicyMachineryController(manager ctrlruntime.Manager, client *dynamic.D ) } - ok, err = envoygateway.IsEnvoyGatewayInstalled(manager.GetRESTMapper()) - if err != nil || !ok { + isEnvoyGatewayInstalled, err := envoygateway.IsEnvoyGatewayInstalled(manager.GetRESTMapper()) + if err != nil || !isEnvoyGatewayInstalled { logger.Info("envoygateway is not installed, skipping related watches and reconcilers", "err", err) } else { controllerOpts = append(controllerOpts, @@ -104,8 +97,8 @@ func NewPolicyMachineryController(manager ctrlruntime.Manager, client *dynamic.D // TODO: add specific tasks to workflow } - ok, err = istio.IsIstioInstalled(manager.GetRESTMapper()) - if err != nil || !ok { + isIstioInstalled, err := istio.IsIstioInstalled(manager.GetRESTMapper()) + if err != nil || !isIstioInstalled { logger.Info("istio is not installed, skipping related watches and reconcilers", "err", err) } else { controllerOpts = append(controllerOpts, @@ -140,119 +133,54 @@ func NewPolicyMachineryController(manager ctrlruntime.Manager, client *dynamic.D // TODO: add tls policy specific tasks to workflow } + controllerOpts = append(controllerOpts, controller.WithReconcile(buildReconciler(client, isIstioInstalled, isEnvoyGatewayInstalled))) + return controller.NewController(controllerOpts...) } -func buildReconciler(client *dynamic.DynamicClient) controller.ReconcileFunc { - reconciler := &controller.Workflow{ - Precondition: (&controller.Workflow{ - Precondition: NewEventLogger().Log, - Tasks: []controller.ReconcileFunc{ - NewTopologyFileReconciler(client, operatorNamespace).Reconcile, - }, - }).Run, +func buildReconciler(client *dynamic.DynamicClient, isIstioInstalled, isEnvoyGatewayInstalled bool) controller.ReconcileFunc { + mainWorkflow := &controller.Workflow{ + Precondition: initWorkflow(client).Run, Tasks: []controller.ReconcileFunc{ - NewAuthorinoCrReconciler(client).Subscription().Reconcile, + NewAuthorinoReconciler(client).Subscription().Reconcile, + NewLimitadorReconciler(client).Subscription().Reconcile, + NewDNSWorkflow().Run, + NewTLSWorkflow().Run, + NewAuthWorkflow().Run, + NewRateLimitWorkflow().Run, }, + Postcondition: finalStepsWorkflow(client, isIstioInstalled, isEnvoyGatewayInstalled).Run, } - return reconciler.Run -} -type TopologyFileReconciler struct { - Client *dynamic.DynamicClient - Namespace string + return mainWorkflow.Run } -func NewTopologyFileReconciler(client *dynamic.DynamicClient, namespace string) *TopologyFileReconciler { - if namespace == "" { - panic("namespace must be specified and can not be a blank string") +func initWorkflow(client *dynamic.DynamicClient) *controller.Workflow { + return &controller.Workflow{ + Precondition: NewEventLogger().Log, + Tasks: []controller.ReconcileFunc{ + NewTopologyReconciler(client, operatorNamespace).Reconcile, + }, } - return &TopologyFileReconciler{Client: client, Namespace: namespace} } -func (r *TopologyFileReconciler) Reconcile(ctx context.Context, _ []controller.ResourceEvent, topology *machinery.Topology, _ error, _ *sync.Map) error { - logger := controller.LoggerFromContext(ctx).WithName("topology file") - - cm := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "topology", - Namespace: r.Namespace, - Labels: map[string]string{kuadrant.TopologyLabel: "true"}, - }, - Data: map[string]string{ - "topology": topology.ToDot(), +func finalStepsWorkflow(client *dynamic.DynamicClient, isIstioInstalled, isEnvoyGatewayInstalled bool) *controller.Workflow { + workflow := &controller.Workflow{ + Tasks: []controller.ReconcileFunc{ + NewGatewayPolicyDiscoverabilityReconciler(client).Subscription().Reconcile, + NewHTTPRoutePolicyDiscoverabilityReconciler(client).Subscription().Reconcile, }, } - unstructuredCM, err := controller.Destruct(cm) - if err != nil { - logger.Error(err, "failed to destruct topology configmap") - return err - } - - existingTopologyConfigMaps := topology.Objects().Items(func(object machinery.Object) bool { - return object.GetName() == cm.GetName() && object.GetNamespace() == cm.GetNamespace() && object.GroupVersionKind().Kind == ConfigMapGroupKind.Kind - }) - - if len(existingTopologyConfigMaps) == 0 { - _, err = r.Client.Resource(controller.ConfigMapsResource).Namespace(cm.Namespace).Create(ctx, unstructuredCM, metav1.CreateOptions{}) - if err != nil { - if errors.IsAlreadyExists(err) { - // This error can happen when the operator is starting, and the create event for the topology has not being processed. - logger.Info("already created topology configmap, must not be in topology yet") - return err - } - logger.Error(err, "failed to write topology configmap") - } - return err - } - - if len(existingTopologyConfigMaps) > 1 { - logger.Info("multiple topology configmaps found, continuing but unexpected behaviour may occur") - } - existingTopologyConfigMap := existingTopologyConfigMaps[0].(controller.Object).(*controller.RuntimeObject) - cmTopology := existingTopologyConfigMap.Object.(*corev1.ConfigMap) - if d, found := cmTopology.Data["topology"]; !found || strings.Compare(d, cm.Data["topology"]) != 0 { - _, err = r.Client.Resource(controller.ConfigMapsResource).Namespace(cm.Namespace).Update(ctx, unstructuredCM, metav1.UpdateOptions{}) - if err != nil { - logger.Error(err, "failed to update topology configmap") - } - return err + if isIstioInstalled { + workflow.Tasks = append(workflow.Tasks, NewIstioExtensionsJanitor(client).Subscription().Reconcile) } - return nil -} - -type EventLogger struct{} - -func NewEventLogger() *EventLogger { - return &EventLogger{} -} - -func (e *EventLogger) Log(ctx context.Context, resourceEvents []controller.ResourceEvent, _ *machinery.Topology, err error, _ *sync.Map) error { - logger := controller.LoggerFromContext(ctx).WithName("event logger") - for _, event := range resourceEvents { - // log the event - obj := event.OldObject - if obj == nil { - obj = event.NewObject - } - values := []any{ - "type", event.EventType.String(), - "kind", obj.GetObjectKind().GroupVersionKind().Kind, - "namespace", obj.GetNamespace(), - "name", obj.GetName(), - } - if event.EventType == controller.UpdateEvent && logger.V(1).Enabled() { - values = append(values, "diff", cmp.Diff(event.OldObject, event.NewObject)) - } - logger.Info("new event", values...) - if err != nil { - logger.Error(err, "error passed to reconcile") - } + if isEnvoyGatewayInstalled { + workflow.Tasks = append(workflow.Tasks, NewEnvoyGatewayJanitor(client).Subscription().Reconcile) } - return nil + return workflow } // GetOldestKuadrant returns the oldest kuadrant resource from a list of kuadrant resources that is not marked for deletion. diff --git a/controllers/tls_workflow.go b/controllers/tls_workflow.go new file mode 100644 index 000000000..40c1f4f68 --- /dev/null +++ b/controllers/tls_workflow.go @@ -0,0 +1,9 @@ +package controllers + +import ( + "github.com/kuadrant/policy-machinery/controller" +) + +func NewTLSWorkflow() *controller.Workflow { + return &controller.Workflow{} +} diff --git a/controllers/topology_reconciler.go b/controllers/topology_reconciler.go new file mode 100644 index 000000000..e61655717 --- /dev/null +++ b/controllers/topology_reconciler.go @@ -0,0 +1,78 @@ +package controllers + +import ( + "context" + "strings" + "sync" + + "github.com/kuadrant/policy-machinery/controller" + "github.com/kuadrant/policy-machinery/machinery" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/dynamic" + + "github.com/kuadrant/kuadrant-operator/pkg/library/kuadrant" +) + +type TopologyReconciler struct { + Client *dynamic.DynamicClient + Namespace string +} + +func NewTopologyReconciler(client *dynamic.DynamicClient, namespace string) *TopologyReconciler { + if namespace == "" { + panic("namespace must be specified and can not be a blank string") + } + return &TopologyReconciler{Client: client, Namespace: namespace} +} + +func (r *TopologyReconciler) Reconcile(ctx context.Context, _ []controller.ResourceEvent, topology *machinery.Topology, _ error, _ *sync.Map) error { + logger := controller.LoggerFromContext(ctx).WithName("topology file") + + cm := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "topology", + Namespace: r.Namespace, + Labels: map[string]string{kuadrant.TopologyLabel: "true"}, + }, + Data: map[string]string{ + "topology": topology.ToDot(), + }, + } + unstructuredCM, err := controller.Destruct(cm) + if err != nil { + logger.Error(err, "failed to destruct topology configmap") + return err + } + + existingTopologyConfigMaps := topology.Objects().Items(func(object machinery.Object) bool { + return object.GetName() == cm.GetName() && object.GetNamespace() == cm.GetNamespace() && object.GroupVersionKind().Kind == ConfigMapGroupKind.Kind + }) + + if len(existingTopologyConfigMaps) == 0 { + _, err := r.Client.Resource(controller.ConfigMapsResource).Namespace(cm.Namespace).Create(ctx, unstructuredCM, metav1.CreateOptions{}) + if errors.IsAlreadyExists(err) { + // This error can happen when the operator is starting, and the create event for the topology has not being processed. + logger.Info("already created topology configmap, must not be in topology yet") + return err + } + return err + } + + if len(existingTopologyConfigMaps) > 1 { + logger.Info("multiple topology configmaps found, continuing but unexpected behaviour may occur") + } + existingTopologyConfigMap := existingTopologyConfigMaps[0].(controller.Object).(*controller.RuntimeObject) + cmTopology := existingTopologyConfigMap.Object.(*corev1.ConfigMap) + + if d, found := cmTopology.Data["topology"]; !found || strings.Compare(d, cm.Data["topology"]) != 0 { + _, err := r.Client.Resource(controller.ConfigMapsResource).Namespace(cm.Namespace).Update(ctx, unstructuredCM, metav1.UpdateOptions{}) + if err != nil { + logger.Error(err, "failed to update topology configmap") + } + return err + } + + return nil +}