From 12ee85499a4ebc8e52e127841b6ffdf06e6f285e Mon Sep 17 00:00:00 2001 From: "assaf.admi" Date: Tue, 7 Jan 2025 17:26:32 +0200 Subject: [PATCH] Add TCOLogsPolicies CRD --- PROJECT | 9 + .../v1alpha1/tcologspolicies_types.go | 197 ++++++++++++++++++ .../v1alpha1/zz_generated.deepcopy.go | 156 ++++++++++++++ cmd/main.go | 8 + .../bases/coralogix.com_tcologspolicies.yaml | 122 +++++++++++ config/crd/kustomization.yaml | 2 + ...coralogix_tcologspolicies_editor_role.yaml | 27 +++ ...coralogix_tcologspolicies_viewer_role.yaml | 23 ++ config/rbac/role.yaml | 26 +++ .../example-tco-logs-policies.yaml | 25 +++ go.mod | 2 +- go.sum | 4 +- .../coralogix/tcologspolicies_controller.go | 130 ++++++++++++ 13 files changed, 728 insertions(+), 3 deletions(-) create mode 100644 api/coralogix/v1alpha1/tcologspolicies_types.go create mode 100644 config/crd/bases/coralogix.com_tcologspolicies.yaml create mode 100644 config/rbac/coralogix_tcologspolicies_editor_role.yaml create mode 100644 config/rbac/coralogix_tcologspolicies_viewer_role.yaml create mode 100644 config/samples/tcologspolicies/example-tco-logs-policies.yaml create mode 100644 internal/controller/coralogix/tcologspolicies_controller.go diff --git a/PROJECT b/PROJECT index 2437100..773e36b 100644 --- a/PROJECT +++ b/PROJECT @@ -90,4 +90,13 @@ resources: kind: Group path: github.com/coralogix/coralogix-operator/api/coralogix/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: coralogix.com + group: coralogix + kind: TCOLogsPolicies + path: github.com/coralogix/coralogix-operator/api/coralogix/v1alpha1 + version: v1alpha1 version: "3" diff --git a/api/coralogix/v1alpha1/tcologspolicies_types.go b/api/coralogix/v1alpha1/tcologspolicies_types.go new file mode 100644 index 0000000..64c5e94 --- /dev/null +++ b/api/coralogix/v1alpha1/tcologspolicies_types.go @@ -0,0 +1,197 @@ +// Copyright 2024 Coralogix Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha1 + +import ( + "errors" + "fmt" + "strings" + + "google.golang.org/protobuf/types/known/wrapperspb" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + cxsdk "github.com/coralogix/coralogix-management-sdk/go" + + utils "github.com/coralogix/coralogix-operator/api" +) + +// TCOLogsPoliciesSpec defines the desired state of TCOLogsPolicies. +type TCOLogsPoliciesSpec struct { + Policies []TCOLogsPolicy `json:"policies"` +} + +type TCOLogsPolicy struct { + Name string `json:"name"` + + // +optional + Description *string `json:"description,omitempty"` + + // +optional + //+kubebuilder:default=true + Enabled bool `json:"enabled"` + + // +kubebuilder:validation:Enum=block;high;medium;low + Priority string `json:"priority"` + + Severities []TCOLogsPolicySeverity `json:"severities"` + + // +optional + ArchiveRetentionID *string `json:"archiveRetentionId,omitempty"` + + // +optional + Applications *TCOLogsPolicyRule `json:"applications,omitempty"` + + // +optional + Subsystems *TCOLogsPolicyRule `json:"subsystems,omitempty"` +} + +// +kubebuilder:validation:Enum=info;warning;critical;error;debug;verbose +type TCOLogsPolicySeverity string + +type TCOLogsPolicyRule struct { + Names []string `json:"names"` + + // +kubebuilder:validation:Enum=is;is_not;starts_with;includes + RuleType string `json:"ruleType"` +} + +func (s *TCOLogsPoliciesSpec) ExtractOverwriteLogPoliciesRequest() (*cxsdk.AtomicOverwriteLogPoliciesRequest, error) { + var policies []*cxsdk.CreateLogPolicyRequest + var errs error + + for _, policy := range s.Policies { + policyReq, err := policy.ExtractCreateLogPolicyRequest() + if err != nil { + errs = errors.Join(errs, err) + } + policies = append(policies, policyReq) + } + + if errs != nil { + return nil, errs + } + + return &cxsdk.AtomicOverwriteLogPoliciesRequest{Policies: policies}, nil +} + +func (p *TCOLogsPolicy) ExtractCreateLogPolicyRequest() (*cxsdk.CreateLogPolicyRequest, error) { + var errs error + priority, err := expandTCOLogsPolicyPriority(p.Priority) + if err != nil { + errs = errors.Join(errs, err) + } + + applicationRule, err := expandTCOLogsPolicyRule(p.Applications) + if err != nil { + errs = errors.Join(errs, err) + } + + subsystemRule, err := expandTCOLogsPolicyRule(p.Subsystems) + if err != nil { + errs = errors.Join(errs, err) + } + + severities, err := expandTCOLogsPolicySeverities(p.Severities) + if err != nil { + errs = errors.Join(errs, err) + } + + if errs != nil { + return nil, errs + } + + req := &cxsdk.CreateLogPolicyRequest{ + Policy: &cxsdk.CreateGenericPolicyRequest{ + Name: wrapperspb.String(p.Name), + Description: utils.StringPointerToWrapperspbString(p.Description), + Priority: priority, + ApplicationRule: applicationRule, + SubsystemRule: subsystemRule, + ArchiveRetention: &cxsdk.ArchiveRetention{ + Id: utils.StringPointerToWrapperspbString(p.ArchiveRetentionID), + }, + }, + LogRules: &cxsdk.TCOLogRules{ + Severities: severities, + }, + } + + return req, nil +} + +func expandTCOLogsPolicyPriority(priority string) (cxsdk.TCOPolicyPriority, error) { + priorityValue, ok := cxsdk.LogPolicyPriorityValueLookup["PRIORITY_TYPE_"+strings.ToUpper(priority)] + if !ok { + return 0, fmt.Errorf("invalid priority for TCOLogsPolicy: %s", priority) + } + return cxsdk.TCOPolicyPriority(priorityValue), nil +} + +func expandTCOLogsPolicyRule(rule *TCOLogsPolicyRule) (*cxsdk.TCOPolicyRule, error) { + if rule == nil { + return nil, nil + } + + ruleType, ok := cxsdk.LogPolicyRuleTypeValueLookup["RULE_TYPE_ID_"+strings.ToUpper(rule.RuleType)] + if !ok { + return nil, fmt.Errorf("invalid rule type for TCOLogsPolicyRule: %s", rule.RuleType) + } + + return &cxsdk.TCOPolicyRule{ + Name: wrapperspb.String(strings.Join(rule.Names, ",")), + RuleTypeId: cxsdk.TCOPolicyRuleTypeID(ruleType), + }, nil +} + +func expandTCOLogsPolicySeverities(severities []TCOLogsPolicySeverity) ([]cxsdk.TCOPolicySeverity, error) { + var result []cxsdk.TCOPolicySeverity + for _, severity := range severities { + severityValue, ok := cxsdk.LogPolicySeverityValueLookup["SEVERITY_"+strings.ToUpper(string(severity))] + if !ok { + return nil, fmt.Errorf("invalid severity for TCOLogsPolicySeverity: %s", severity) + } + result = append(result, cxsdk.TCOPolicySeverity(severityValue)) + } + + return result, nil +} + +// TCOLogsPoliciesStatus defines the observed state of TCOLogsPolicies. +type TCOLogsPoliciesStatus struct{} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status + +// TCOLogsPolicies is the Schema for the tcologspolicies API. +type TCOLogsPolicies struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec TCOLogsPoliciesSpec `json:"spec,omitempty"` + Status TCOLogsPoliciesStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// TCOLogsPoliciesList contains a list of TCOLogsPolicies. +type TCOLogsPoliciesList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TCOLogsPolicies `json:"items"` +} + +func init() { + SchemeBuilder.Register(&TCOLogsPolicies{}, &TCOLogsPoliciesList{}) +} diff --git a/api/coralogix/v1alpha1/zz_generated.deepcopy.go b/api/coralogix/v1alpha1/zz_generated.deepcopy.go index e18c861..647bf61 100644 --- a/api/coralogix/v1alpha1/zz_generated.deepcopy.go +++ b/api/coralogix/v1alpha1/zz_generated.deepcopy.go @@ -2279,6 +2279,162 @@ func (in *StandardConditions) DeepCopy() *StandardConditions { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TCOLogsPolicies) DeepCopyInto(out *TCOLogsPolicies) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCOLogsPolicies. +func (in *TCOLogsPolicies) DeepCopy() *TCOLogsPolicies { + if in == nil { + return nil + } + out := new(TCOLogsPolicies) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TCOLogsPolicies) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TCOLogsPoliciesList) DeepCopyInto(out *TCOLogsPoliciesList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TCOLogsPolicies, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCOLogsPoliciesList. +func (in *TCOLogsPoliciesList) DeepCopy() *TCOLogsPoliciesList { + if in == nil { + return nil + } + out := new(TCOLogsPoliciesList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TCOLogsPoliciesList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TCOLogsPoliciesSpec) DeepCopyInto(out *TCOLogsPoliciesSpec) { + *out = *in + if in.Policies != nil { + in, out := &in.Policies, &out.Policies + *out = make([]TCOLogsPolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCOLogsPoliciesSpec. +func (in *TCOLogsPoliciesSpec) DeepCopy() *TCOLogsPoliciesSpec { + if in == nil { + return nil + } + out := new(TCOLogsPoliciesSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TCOLogsPoliciesStatus) DeepCopyInto(out *TCOLogsPoliciesStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCOLogsPoliciesStatus. +func (in *TCOLogsPoliciesStatus) DeepCopy() *TCOLogsPoliciesStatus { + if in == nil { + return nil + } + out := new(TCOLogsPoliciesStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TCOLogsPolicy) DeepCopyInto(out *TCOLogsPolicy) { + *out = *in + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.Severities != nil { + in, out := &in.Severities, &out.Severities + *out = make([]TCOLogsPolicySeverity, len(*in)) + copy(*out, *in) + } + if in.ArchiveRetentionID != nil { + in, out := &in.ArchiveRetentionID, &out.ArchiveRetentionID + *out = new(string) + **out = **in + } + if in.Applications != nil { + in, out := &in.Applications, &out.Applications + *out = new(TCOLogsPolicyRule) + (*in).DeepCopyInto(*out) + } + if in.Subsystems != nil { + in, out := &in.Subsystems, &out.Subsystems + *out = new(TCOLogsPolicyRule) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCOLogsPolicy. +func (in *TCOLogsPolicy) DeepCopy() *TCOLogsPolicy { + if in == nil { + return nil + } + out := new(TCOLogsPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TCOLogsPolicyRule) DeepCopyInto(out *TCOLogsPolicyRule) { + *out = *in + if in.Names != nil { + in, out := &in.Names, &out.Names + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TCOLogsPolicyRule. +func (in *TCOLogsPolicyRule) DeepCopy() *TCOLogsPolicyRule { + if in == nil { + return nil + } + out := new(TCOLogsPolicyRule) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TagFilter) DeepCopyInto(out *TagFilter) { *out = *in diff --git a/cmd/main.go b/cmd/main.go index c7a3878..bef3c75 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -284,6 +284,14 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "Group") os.Exit(1) } + if err = (&coralogixcontrollers.TCOLogsPoliciesReconciler{ + TCOClient: sdkClientSet.TCOPolicies(), + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "TCOLogsPolicies") + os.Exit(1) + } if prometheusRuleController { if err = (&controllers.AlertmanagerConfigReconciler{ diff --git a/config/crd/bases/coralogix.com_tcologspolicies.yaml b/config/crd/bases/coralogix.com_tcologspolicies.yaml new file mode 100644 index 0000000..8de1006 --- /dev/null +++ b/config/crd/bases/coralogix.com_tcologspolicies.yaml @@ -0,0 +1,122 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: tcologspolicies.coralogix.com +spec: + group: coralogix.com + names: + kind: TCOLogsPolicies + listKind: TCOLogsPoliciesList + plural: tcologspolicies + singular: tcologspolicies + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: TCOLogsPolicies is the Schema for the tcologspolicies API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TCOLogsPoliciesSpec defines the desired state of TCOLogsPolicies. + properties: + policies: + items: + properties: + applications: + properties: + names: + items: + type: string + type: array + ruleType: + enum: + - is + - is_not + - starts_with + - includes + type: string + required: + - names + - ruleType + type: object + archiveRetentionId: + type: string + description: + type: string + enabled: + default: true + type: boolean + name: + type: string + priority: + enum: + - block + - high + - medium + - low + type: string + severities: + items: + enum: + - info + - warning + - critical + - error + - debug + - verbose + type: string + type: array + subsystems: + properties: + names: + items: + type: string + type: array + ruleType: + enum: + - is + - is_not + - starts_with + - includes + type: string + required: + - names + - ruleType + type: object + required: + - name + - priority + - severities + type: object + type: array + required: + - policies + type: object + status: + description: TCOLogsPoliciesStatus defines the observed state of TCOLogsPolicies. + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index ae60f51..d477513 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -10,6 +10,7 @@ resources: - bases/coralogix.com_customroles.yaml - bases/coralogix.com_scopes.yaml - bases/coralogix.com_groups.yaml + - bases/coralogix.com_tcologspolicies.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -31,6 +32,7 @@ patchesStrategicMerge: #- patches/cainjection_in_coralogix_customroles.yaml #- patches/cainjection_in_coralogix_scopes.yaml #- patches/cainjection_in_coralogix_groups.yaml +#- patches/cainjection_in_coralogix_tcologspolicies.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/rbac/coralogix_tcologspolicies_editor_role.yaml b/config/rbac/coralogix_tcologspolicies_editor_role.yaml new file mode 100644 index 0000000..f818bcf --- /dev/null +++ b/config/rbac/coralogix_tcologspolicies_editor_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to edit tcologspolicies. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: coralogix-operator + app.kubernetes.io/managed-by: kustomize + name: coralogix-tcologspolicies-editor-role +rules: +- apiGroups: + - coralogix.com + resources: + - tcologspolicies + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - coralogix.com + resources: + - tcologspolicies/status + verbs: + - get diff --git a/config/rbac/coralogix_tcologspolicies_viewer_role.yaml b/config/rbac/coralogix_tcologspolicies_viewer_role.yaml new file mode 100644 index 0000000..ad146fe --- /dev/null +++ b/config/rbac/coralogix_tcologspolicies_viewer_role.yaml @@ -0,0 +1,23 @@ +# permissions for end users to view tcologspolicies. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: coralogix-operator + app.kubernetes.io/managed-by: kustomize + name: coralogix-tcologspolicies-viewer-role +rules: +- apiGroups: + - coralogix.com + resources: + - tcologspolicies + verbs: + - get + - list + - watch +- apiGroups: + - coralogix.com + resources: + - tcologspolicies/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 309ca0c..347fa97 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -224,6 +224,32 @@ rules: - get - patch - update +- apiGroups: + - coralogix.com + resources: + - tcologspolicies + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - coralogix.com + resources: + - tcologspolicies/finalizers + verbs: + - update +- apiGroups: + - coralogix.com + resources: + - tcologspolicies/status + verbs: + - get + - patch + - update - apiGroups: - monitoring.coreos.com resources: diff --git a/config/samples/tcologspolicies/example-tco-logs-policies.yaml b/config/samples/tcologspolicies/example-tco-logs-policies.yaml new file mode 100644 index 0000000..4a53e1f --- /dev/null +++ b/config/samples/tcologspolicies/example-tco-logs-policies.yaml @@ -0,0 +1,25 @@ +apiVersion: coralogix.com/v1alpha1 +kind: TCOLogsPolicies +metadata: + labels: + app.kubernetes.io/name: coralogix-operator + app.kubernetes.io/instance: tco-logs-policies-sample + app.kubernetes.io/part-of: coralogix-operator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: coralogix-operator + name: tco-logs-policies-sample +spec: + policies: + - name: first policy + priority: high + severities: + - critical + - error + applications: + names: + - prod + ruleType: is + subsystems: + names: + - mobile + ruleType: is diff --git a/go.mod b/go.mod index 861ff0c..38a07a3 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/coralogix/coralogix-operator go 1.23.0 require ( - github.com/coralogix/coralogix-management-sdk v0.12.2-0.20250106131343-1086b344cdf2 + github.com/coralogix/coralogix-management-sdk v0.12.2-0.20250107155155-79c840a5497c github.com/go-logr/logr v1.4.2 github.com/golang/protobuf v1.5.4 github.com/google/uuid v1.6.0 diff --git a/go.sum b/go.sum index c808cb8..3149cd5 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/coralogix/coralogix-management-sdk v0.12.2-0.20250106131343-1086b344cdf2 h1:xhhq+UIpqqA/opE3TSiUlvBuwf8mOtSPnn6+xvCO1rk= -github.com/coralogix/coralogix-management-sdk v0.12.2-0.20250106131343-1086b344cdf2/go.mod h1:4j43DiCGPC8pQghrZRgQp+V3dTzObZ2ohRXswnRkIrE= +github.com/coralogix/coralogix-management-sdk v0.12.2-0.20250107155155-79c840a5497c h1:VfdVfW1lT1tFAtcZFG5SKzd4UhLTEXBw/MyBl3/IJe0= +github.com/coralogix/coralogix-management-sdk v0.12.2-0.20250107155155-79c840a5497c/go.mod h1:4j43DiCGPC8pQghrZRgQp+V3dTzObZ2ohRXswnRkIrE= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/controller/coralogix/tcologspolicies_controller.go b/internal/controller/coralogix/tcologspolicies_controller.go new file mode 100644 index 0000000..7c66e4d --- /dev/null +++ b/internal/controller/coralogix/tcologspolicies_controller.go @@ -0,0 +1,130 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package coralogix + +import ( + "context" + "fmt" + "github.com/go-logr/logr" + "google.golang.org/grpc/codes" + "google.golang.org/protobuf/encoding/protojson" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + + cxsdk "github.com/coralogix/coralogix-management-sdk/go" + + coralogixv1alpha1 "github.com/coralogix/coralogix-operator/api/coralogix/v1alpha1" +) + +// TCOLogsPoliciesReconciler reconciles a TCOLogsPolicies object +type TCOLogsPoliciesReconciler struct { + client.Client + TCOClient *cxsdk.TCOPoliciesClient + Scheme *runtime.Scheme +} + +// +kubebuilder:rbac:groups=coralogix.com,resources=tcologspolicies,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=coralogix.com,resources=tcologspolicies/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=coralogix.com,resources=tcologspolicies/finalizers,verbs=update + +var ( + tcoLogsPoliciesFinalizerName = "tco-logs-policies.coralogix.com/finalizer" +) + +func (r *TCOLogsPoliciesReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := log.FromContext(ctx).WithValues( + "tcoLogsPolicies", req.NamespacedName.Name, + "namespace", req.NamespacedName.Namespace, + ) + + tcoLogsPolicies := &coralogixv1alpha1.TCOLogsPolicies{} + if err := r.Get(ctx, req.NamespacedName, tcoLogsPolicies); err != nil { + if errors.IsNotFound(err) { + // Request object not found, could have been deleted after reconcile request. + // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. + // Return and don't requeue + return ctrl.Result{}, nil + } + return ctrl.Result{RequeueAfter: defaultErrRequeuePeriod}, err + } + + if !tcoLogsPolicies.ObjectMeta.DeletionTimestamp.IsZero() { + err := r.delete(ctx, log, tcoLogsPolicies) + if err != nil { + log.Error(err, "Error on deleting TCOLogsPolicies") + return ctrl.Result{RequeueAfter: defaultErrRequeuePeriod}, err + } + return ctrl.Result{}, nil + } + + err := r.overwrite(ctx, log, tcoLogsPolicies) + if err != nil { + log.Error(err, "Error on overwriting TCOLogsPolicies") + return ctrl.Result{RequeueAfter: defaultErrRequeuePeriod}, err + } + + return ctrl.Result{}, nil +} + +func (r *TCOLogsPoliciesReconciler) overwrite(ctx context.Context, log logr.Logger, tcoLogsPolicies *coralogixv1alpha1.TCOLogsPolicies) error { + overwriteRequest, err := tcoLogsPolicies.Spec.ExtractOverwriteLogPoliciesRequest() + if err != nil { + return fmt.Errorf("error on extracting overwrite log policies request: %w", err) + } + log.V(1).Info("Overwriting remote tco-logs-policies", "tco-logs-policies", protojson.Format(overwriteRequest)) + createResponse, err := r.TCOClient.OverwriteTCOLogsPolicies(ctx, overwriteRequest) + if err != nil { + return fmt.Errorf("error on overwriting remote tco-logs-policies: %w", err) + } + log.V(1).Info("Remote tco-logs-policies overwritten", "response", protojson.Format(createResponse)) + + if !controllerutil.ContainsFinalizer(tcoLogsPolicies, tcoLogsPoliciesFinalizerName) { + log.V(1).Info("Updating TCOLogsPolicies to add finalizer", "name", tcoLogsPolicies.Name) + controllerutil.AddFinalizer(tcoLogsPolicies, tcoLogsPoliciesFinalizerName) + if err = r.Update(ctx, tcoLogsPolicies); err != nil { + return fmt.Errorf("error on updating TCOLogsPolicies: %w", err) + } + } + + return nil +} + +func (r *TCOLogsPoliciesReconciler) delete(ctx context.Context, log logr.Logger, tcoLogsPolicies *coralogixv1alpha1.TCOLogsPolicies) error { + if _, err := r.TCOClient.OverwriteTCOLogsPolicies(ctx, &cxsdk.AtomicOverwriteLogPoliciesRequest{}); err != nil && cxsdk.Code(err) != codes.NotFound { + return fmt.Errorf("error to delete remote tco-logs-policies: %w", err) + } + log.V(1).Info("tco-logs-policies was deleted from remote", "name", tcoLogsPolicies.Name) + + log.V(1).Info("Removing finalizer from TCOLogsPolicies") + controllerutil.RemoveFinalizer(tcoLogsPolicies, tcoLogsPoliciesFinalizerName) + if err := r.Update(ctx, tcoLogsPolicies); err != nil { + return fmt.Errorf("error on updating TCOLogsPolicies: %w", err) + } + + return nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *TCOLogsPoliciesReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&coralogixv1alpha1.TCOLogsPolicies{}). + Complete(r) +}