diff --git a/charts/logging-operator/crds/logging.banzaicloud.io_fluentdconfigs.yaml b/charts/logging-operator/crds/logging.banzaicloud.io_fluentdconfigs.yaml new file mode 100644 index 000000000..fe993b466 --- /dev/null +++ b/charts/logging-operator/crds/logging.banzaicloud.io_fluentdconfigs.yaml @@ -0,0 +1,2918 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.0 + creationTimestamp: null + name: fluentdconfigs.logging.banzaicloud.io +spec: + group: logging.banzaicloud.io + names: + categories: + - logging-all + kind: FluentdConfig + listKind: FluentdConfigList + plural: fluentdconfigs + singular: fluentdconfig + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Is the fluentd configuration active? + jsonPath: .status.active + name: Active + type: boolean + - description: Number of problems + jsonPath: .status.problemsCount + name: Problems + type: integer + name: v1beta1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + affinity: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + type: array + required: + - nodeSelectorTerms + type: object + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + annotations: + additionalProperties: + type: string + type: object + bufferStorageVolume: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + host_path: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + pvc: + properties: + source: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + storageClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + optional: + type: boolean + secretName: + type: string + type: object + type: object + bufferVolumeArgs: + items: + type: string + type: array + bufferVolumeImage: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + bufferVolumeMetrics: + properties: + interval: + type: string + path: + type: string + port: + format: int32 + type: integer + prometheusAnnotations: + type: boolean + prometheusRules: + type: boolean + serviceMonitor: + type: boolean + serviceMonitorConfig: + properties: + additionalLabels: + additionalProperties: + type: string + type: object + honorLabels: + type: boolean + metricRelabelings: + items: + properties: + action: + default: replace + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + format: int64 + type: integer + regex: + type: string + replacement: + type: string + separator: + type: string + sourceLabels: + items: + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + type: string + type: object + type: array + relabelings: + items: + properties: + action: + default: replace + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + format: int64 + type: integer + regex: + type: string + replacement: + type: string + separator: + type: string + sourceLabels: + items: + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + type: string + type: object + type: array + scheme: + type: string + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + secret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + secret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + serverName: + type: string + type: object + type: object + timeout: + type: string + type: object + bufferVolumeResources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + compressConfigFile: + type: boolean + configCheckAnnotations: + additionalProperties: + type: string + type: object + configCheckResources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + configReloaderImage: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + configReloaderResources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + disablePvc: + type: boolean + dnsConfig: + properties: + nameservers: + items: + type: string + type: array + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + searches: + items: + type: string + type: array + type: object + dnsPolicy: + type: string + enableMsgpackTimeSupport: + type: boolean + envVars: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + extraArgs: + items: + type: string + type: array + extraVolumes: + items: + properties: + containerName: + type: string + path: + type: string + volume: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + host_path: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + pvc: + properties: + source: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + storageClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + optional: + type: boolean + secretName: + type: string + type: object + type: object + volumeName: + type: string + type: object + type: array + fluentLogDestination: + type: string + fluentOutLogrotate: + properties: + age: + type: string + enabled: + type: boolean + path: + type: string + size: + type: string + required: + - enabled + type: object + fluentdPvcSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + host_path: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + pvc: + properties: + source: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + storageClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + optional: + type: boolean + secretName: + type: string + type: object + type: object + forwardInputConfig: + properties: + add_tag_prefix: + type: string + bind: + type: string + chunk_size_limit: + type: string + chunk_size_warn_limit: + type: string + deny_keepalive: + type: boolean + linger_timeout: + type: integer + port: + type: string + resolve_hostname: + type: boolean + security: + properties: + allow_anonymous_source: + type: boolean + self_hostname: + type: string + shared_key: + type: string + user_auth: + type: boolean + required: + - self_hostname + - shared_key + type: object + send_keepalive_packet: + type: boolean + skip_invalid_event: + type: boolean + source_address_key: + type: string + sourceHostnameKey: + type: string + tag: + type: string + transport: + properties: + ca_cert_path: + type: string + ca_path: + type: string + ca_private_key_passphrase: + type: string + ca_private_key_path: + type: string + cert_path: + type: string + ciphers: + type: string + client_cert_auth: + type: boolean + insecure: + type: boolean + private_key_passphrase: + type: string + private_key_path: + type: string + protocol: + type: string + version: + type: string + type: object + type: object + ignoreRepeatedLogInterval: + type: string + ignoreSameLogInterval: + type: string + image: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + livenessDefaultCheck: + type: boolean + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + logLevel: + type: string + metrics: + properties: + interval: + type: string + path: + type: string + port: + format: int32 + type: integer + prometheusAnnotations: + type: boolean + prometheusRules: + type: boolean + serviceMonitor: + type: boolean + serviceMonitorConfig: + properties: + additionalLabels: + additionalProperties: + type: string + type: object + honorLabels: + type: boolean + metricRelabelings: + items: + properties: + action: + default: replace + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + format: int64 + type: integer + regex: + type: string + replacement: + type: string + separator: + type: string + sourceLabels: + items: + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + type: string + type: object + type: array + relabelings: + items: + properties: + action: + default: replace + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + format: int64 + type: integer + regex: + type: string + replacement: + type: string + separator: + type: string + sourceLabels: + items: + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + type: string + type: object + type: array + scheme: + type: string + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + secret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + secret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + serverName: + type: string + type: object + type: object + timeout: + type: string + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podPriorityClassName: + type: string + port: + format: int32 + type: integer + readinessDefaultCheck: + properties: + bufferFileNumber: + type: boolean + bufferFileNumberMax: + format: int32 + type: integer + bufferFreeSpace: + type: boolean + bufferFreeSpaceThreshold: + format: int32 + type: integer + failureThreshold: + format: int32 + type: integer + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + rootDir: + type: string + scaling: + properties: + drain: + properties: + annotations: + additionalProperties: + type: string + type: object + deleteVolume: + type: boolean + enabled: + type: boolean + image: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + pauseImage: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + type: object + podManagementPolicy: + type: string + replicas: + type: integer + type: object + security: + properties: + podSecurityContext: + properties: + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + podSecurityPolicyCreate: + type: boolean + roleBasedAccessControlCreate: + type: boolean + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + serviceAccount: + type: string + type: object + serviceAccount: + properties: + automountServiceAccountToken: + type: boolean + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + secrets: + items: + properties: + apiVersion: + type: string + fieldPath: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + resourceVersion: + type: string + uid: + type: string + type: object + type: array + type: object + sidecarContainers: + items: + properties: + args: + items: + type: string + type: array + command: + items: + type: string + type: array + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + type: object + type: array + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + type: string + required: + - name + type: object + type: array + statefulsetAnnotations: + additionalProperties: + type: string + type: object + tls: + properties: + enabled: + type: boolean + secretName: + type: string + sharedKey: + type: string + required: + - enabled + type: object + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeModImage: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + volumeMountChmod: + type: boolean + workers: + format: int32 + type: integer + type: object + status: + properties: + active: + type: boolean + logging: + type: string + problems: + items: + type: string + type: array + problemsCount: + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/charts/logging-operator/crds/logging.banzaicloud.io_loggings.yaml b/charts/logging-operator/crds/logging.banzaicloud.io_loggings.yaml index ebefd4ea6..027573523 100644 --- a/charts/logging-operator/crds/logging.banzaicloud.io_loggings.yaml +++ b/charts/logging-operator/crds/logging.banzaicloud.io_loggings.yaml @@ -18679,6 +18679,8 @@ spec: additionalProperties: type: boolean type: object + fluentdConfigName: + type: string problems: items: type: string diff --git a/charts/logging-operator/templates/clusterrole.yaml b/charts/logging-operator/templates/clusterrole.yaml index bb8ab56d3..66bf6b8d7 100644 --- a/charts/logging-operator/templates/clusterrole.yaml +++ b/charts/logging-operator/templates/clusterrole.yaml @@ -241,6 +241,7 @@ rules: - clusteroutputs - flows - fluentbitagents + - fluentdconfigs - loggings - nodeagents - outputs @@ -259,6 +260,7 @@ rules: - clusteroutputs/status - flows/status - fluentbitagents/status + - fluentdconfigs/status - loggings/status - nodeagents/status - outputs/status diff --git a/config/crd/bases/logging.banzaicloud.io_fluentdconfigs.yaml b/config/crd/bases/logging.banzaicloud.io_fluentdconfigs.yaml new file mode 100644 index 000000000..fe993b466 --- /dev/null +++ b/config/crd/bases/logging.banzaicloud.io_fluentdconfigs.yaml @@ -0,0 +1,2918 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.0 + creationTimestamp: null + name: fluentdconfigs.logging.banzaicloud.io +spec: + group: logging.banzaicloud.io + names: + categories: + - logging-all + kind: FluentdConfig + listKind: FluentdConfigList + plural: fluentdconfigs + singular: fluentdconfig + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Is the fluentd configuration active? + jsonPath: .status.active + name: Active + type: boolean + - description: Number of problems + jsonPath: .status.problemsCount + name: Problems + type: integer + name: v1beta1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + affinity: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + type: array + required: + - nodeSelectorTerms + type: object + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + annotations: + additionalProperties: + type: string + type: object + bufferStorageVolume: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + host_path: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + pvc: + properties: + source: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + storageClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + optional: + type: boolean + secretName: + type: string + type: object + type: object + bufferVolumeArgs: + items: + type: string + type: array + bufferVolumeImage: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + bufferVolumeMetrics: + properties: + interval: + type: string + path: + type: string + port: + format: int32 + type: integer + prometheusAnnotations: + type: boolean + prometheusRules: + type: boolean + serviceMonitor: + type: boolean + serviceMonitorConfig: + properties: + additionalLabels: + additionalProperties: + type: string + type: object + honorLabels: + type: boolean + metricRelabelings: + items: + properties: + action: + default: replace + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + format: int64 + type: integer + regex: + type: string + replacement: + type: string + separator: + type: string + sourceLabels: + items: + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + type: string + type: object + type: array + relabelings: + items: + properties: + action: + default: replace + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + format: int64 + type: integer + regex: + type: string + replacement: + type: string + separator: + type: string + sourceLabels: + items: + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + type: string + type: object + type: array + scheme: + type: string + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + secret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + secret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + serverName: + type: string + type: object + type: object + timeout: + type: string + type: object + bufferVolumeResources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + compressConfigFile: + type: boolean + configCheckAnnotations: + additionalProperties: + type: string + type: object + configCheckResources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + configReloaderImage: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + configReloaderResources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + disablePvc: + type: boolean + dnsConfig: + properties: + nameservers: + items: + type: string + type: array + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + searches: + items: + type: string + type: array + type: object + dnsPolicy: + type: string + enableMsgpackTimeSupport: + type: boolean + envVars: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + extraArgs: + items: + type: string + type: array + extraVolumes: + items: + properties: + containerName: + type: string + path: + type: string + volume: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + host_path: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + pvc: + properties: + source: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + storageClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + optional: + type: boolean + secretName: + type: string + type: object + type: object + volumeName: + type: string + type: object + type: array + fluentLogDestination: + type: string + fluentOutLogrotate: + properties: + age: + type: string + enabled: + type: boolean + path: + type: string + size: + type: string + required: + - enabled + type: object + fluentdPvcSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + host_path: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + pvc: + properties: + source: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + storageClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + optional: + type: boolean + secretName: + type: string + type: object + type: object + forwardInputConfig: + properties: + add_tag_prefix: + type: string + bind: + type: string + chunk_size_limit: + type: string + chunk_size_warn_limit: + type: string + deny_keepalive: + type: boolean + linger_timeout: + type: integer + port: + type: string + resolve_hostname: + type: boolean + security: + properties: + allow_anonymous_source: + type: boolean + self_hostname: + type: string + shared_key: + type: string + user_auth: + type: boolean + required: + - self_hostname + - shared_key + type: object + send_keepalive_packet: + type: boolean + skip_invalid_event: + type: boolean + source_address_key: + type: string + sourceHostnameKey: + type: string + tag: + type: string + transport: + properties: + ca_cert_path: + type: string + ca_path: + type: string + ca_private_key_passphrase: + type: string + ca_private_key_path: + type: string + cert_path: + type: string + ciphers: + type: string + client_cert_auth: + type: boolean + insecure: + type: boolean + private_key_passphrase: + type: string + private_key_path: + type: string + protocol: + type: string + version: + type: string + type: object + type: object + ignoreRepeatedLogInterval: + type: string + ignoreSameLogInterval: + type: string + image: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + livenessDefaultCheck: + type: boolean + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + logLevel: + type: string + metrics: + properties: + interval: + type: string + path: + type: string + port: + format: int32 + type: integer + prometheusAnnotations: + type: boolean + prometheusRules: + type: boolean + serviceMonitor: + type: boolean + serviceMonitorConfig: + properties: + additionalLabels: + additionalProperties: + type: string + type: object + honorLabels: + type: boolean + metricRelabelings: + items: + properties: + action: + default: replace + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + format: int64 + type: integer + regex: + type: string + replacement: + type: string + separator: + type: string + sourceLabels: + items: + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + type: string + type: object + type: array + relabelings: + items: + properties: + action: + default: replace + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + format: int64 + type: integer + regex: + type: string + replacement: + type: string + separator: + type: string + sourceLabels: + items: + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + type: string + type: object + type: array + scheme: + type: string + tlsConfig: + properties: + ca: + properties: + configMap: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + secret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + caFile: + type: string + cert: + properties: + configMap: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + secret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + certFile: + type: string + insecureSkipVerify: + type: boolean + keyFile: + type: string + keySecret: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + serverName: + type: string + type: object + type: object + timeout: + type: string + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podPriorityClassName: + type: string + port: + format: int32 + type: integer + readinessDefaultCheck: + properties: + bufferFileNumber: + type: boolean + bufferFileNumberMax: + format: int32 + type: integer + bufferFreeSpace: + type: boolean + bufferFreeSpaceThreshold: + format: int32 + type: integer + failureThreshold: + format: int32 + type: integer + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + rootDir: + type: string + scaling: + properties: + drain: + properties: + annotations: + additionalProperties: + type: string + type: object + deleteVolume: + type: boolean + enabled: + type: boolean + image: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + pauseImage: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + type: object + podManagementPolicy: + type: string + replicas: + type: integer + type: object + security: + properties: + podSecurityContext: + properties: + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + podSecurityPolicyCreate: + type: boolean + roleBasedAccessControlCreate: + type: boolean + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + serviceAccount: + type: string + type: object + serviceAccount: + properties: + automountServiceAccountToken: + type: boolean + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + secrets: + items: + properties: + apiVersion: + type: string + fieldPath: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + resourceVersion: + type: string + uid: + type: string + type: object + type: array + type: object + sidecarContainers: + items: + properties: + args: + items: + type: string + type: array + command: + items: + type: string + type: array + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + type: object + type: array + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + type: string + required: + - name + type: object + type: array + statefulsetAnnotations: + additionalProperties: + type: string + type: object + tls: + properties: + enabled: + type: boolean + secretName: + type: string + sharedKey: + type: string + required: + - enabled + type: object + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeModImage: + properties: + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + pullPolicy: + type: string + repository: + type: string + tag: + type: string + type: object + volumeMountChmod: + type: boolean + workers: + format: int32 + type: integer + type: object + status: + properties: + active: + type: boolean + logging: + type: string + problems: + items: + type: string + type: array + problemsCount: + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/bases/logging.banzaicloud.io_loggings.yaml b/config/crd/bases/logging.banzaicloud.io_loggings.yaml index ebefd4ea6..027573523 100644 --- a/config/crd/bases/logging.banzaicloud.io_loggings.yaml +++ b/config/crd/bases/logging.banzaicloud.io_loggings.yaml @@ -18679,6 +18679,8 @@ spec: additionalProperties: type: boolean type: object + fluentdConfigName: + type: string problems: items: type: string diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index ad88ef178..16f6a752e 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -241,6 +241,7 @@ rules: - clusteroutputs - flows - fluentbitagents + - fluentdconfigs - loggings - nodeagents - outputs @@ -259,6 +260,7 @@ rules: - clusteroutputs/status - flows/status - fluentbitagents/status + - fluentdconfigs/status - loggings/status - nodeagents/status - outputs/status diff --git a/controllers/logging/logging_controller.go b/controllers/logging/logging_controller.go index 6f3cad00f..f80afb492 100644 --- a/controllers/logging/logging_controller.go +++ b/controllers/logging/logging_controller.go @@ -64,8 +64,8 @@ type LoggingReconciler struct { Log logr.Logger } -// +kubebuilder:rbac:groups=logging.banzaicloud.io,resources=loggings;fluentbitagents;flows;clusterflows;outputs;clusteroutputs;nodeagents,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=logging.banzaicloud.io,resources=loggings/status;fluentbitagents/status;flows/status;clusterflows/status;outputs/status;clusteroutputs/status;nodeagents/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=logging.banzaicloud.io,resources=loggings;fluentbitagents;flows;clusterflows;outputs;clusteroutputs;nodeagents;fluentdconfigs,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=logging.banzaicloud.io,resources=loggings/status;fluentbitagents/status;flows/status;clusterflows/status;outputs/status;clusteroutputs/status;nodeagents/status;fluentdconfigs/status,verbs=get;update;patch // +kubebuilder:rbac:groups=logging.banzaicloud.io,resources=syslogngflows;syslogngclusterflows;syslogngoutputs;syslogngclusteroutputs,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=logging.banzaicloud.io,resources=syslogngflows/status;syslogngclusterflows/status;syslogngoutputs/status;syslogngclusteroutputs/status,verbs=get;update;patch // +kubebuilder:rbac:groups="",resources=configmaps;secrets,verbs=get;list;watch;create;update;patch;delete @@ -169,13 +169,14 @@ func (r *LoggingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct ), } - if logging.Spec.FluentdSpec != nil && logging.Spec.SyslogNGSpec != nil { + if logging.AreMultipleAggregatorsSet() { return ctrl.Result{}, errors.New("fluentd and syslogNG cannot be enabled simultaneously") } var loggingDataProvider loggingdataprovider.LoggingDataProvider - if logging.Spec.FluentdSpec != nil { + fluentdSpec := loggingResources.GetFluentdSpec() + if fluentdSpec != nil { fluentdConfig, secretList, err := r.clusterConfigurationFluentd(loggingResources) if err != nil { // TODO: move config generation into Fluentd reconciler @@ -185,9 +186,9 @@ func (r *LoggingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct } else { log.V(1).Info("flow configuration", "config", fluentdConfig) - reconcilers = append(reconcilers, fluentd.New(r.Client, r.Log, &logging, &fluentdConfig, secretList, reconcilerOpts).Reconcile) + reconcilers = append(reconcilers, fluentd.New(r.Client, r.Log, &logging, fluentdSpec, &fluentdConfig, secretList, reconcilerOpts).Reconcile) } - loggingDataProvider = fluentd.NewDataProvider(r.Client, &logging) + loggingDataProvider = fluentd.NewDataProvider(r.Client, &logging, fluentdSpec) } if logging.Spec.SyslogNGSpec != nil { @@ -215,6 +216,7 @@ func (r *LoggingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct r.Client, log.WithName("fluentbit-legacy"), &logging, + fluentdSpec, reconcilerOpts, logging.Spec.FluentbitSpec, loggingDataProvider, @@ -233,6 +235,7 @@ func (r *LoggingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct r.Client, l.WithValues("fluentbitagent", f.Name), &logging, + fluentdSpec, reconcilerOpts, &f.Spec, loggingDataProvider, @@ -257,7 +260,7 @@ func (r *LoggingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct log.Error(errors.New("nodeagent definition conflict"), problem) } } - reconcilers = append(reconcilers, nodeagent.New(r.Client, r.Log, &logging, agents, reconcilerOpts, fluentd.NewDataProvider(r.Client, &logging)).Reconcile) + reconcilers = append(reconcilers, nodeagent.New(r.Client, r.Log, &logging, fluentdSpec, agents, reconcilerOpts, fluentd.NewDataProvider(r.Client, &logging, fluentdSpec)).Reconcile) } for _, rec := range reconcilers { @@ -433,6 +436,8 @@ func SetupLoggingWithManager(mgr ctrl.Manager, logger logr.Logger) *ctrl.Builder return reconcileRequestsForLoggingRef(loggingList.Items, o.Spec.LoggingRef) case *loggingv1beta1.LoggingRoute: return reconcileRequestsForLoggingRef(loggingList.Items, o.Spec.Source) + case *loggingv1beta1.FluentdConfig: + return reconcileRequestsForMatchingControlNamespace(loggingList.Items, o.Namespace) case *corev1.Secret: r := regexp.MustCompile(`^logging\.banzaicloud\.io/(.*)`) var requestList []reconcile.Request @@ -482,7 +487,8 @@ func SetupLoggingWithManager(mgr ctrl.Manager, logger logr.Logger) *ctrl.Builder Watches(&loggingv1beta1.SyslogNGOutput{}, requestMapper). Watches(&loggingv1beta1.SyslogNGFlow{}, requestMapper). Watches(&corev1.Secret{}, requestMapper). - Watches(&loggingv1beta1.LoggingRoute{}, requestMapper) + Watches(&loggingv1beta1.LoggingRoute{}, requestMapper). + Watches(&loggingv1beta1.FluentdConfig{}, requestMapper) // TODO remove with the next major release if os.Getenv("ENABLE_NODEAGENT_CRD") != "" { @@ -514,6 +520,20 @@ func reconcileRequestsForLoggingRef(loggings []loggingv1beta1.Logging, loggingRe return } +func reconcileRequestsForMatchingControlNamespace(loggings []loggingv1beta1.Logging, ControlNamespace string) (reqs []reconcile.Request) { + for _, l := range loggings { + if l.Spec.ControlNamespace == ControlNamespace { + reqs = append(reqs, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: l.Namespace, // this happens to be empty as long as Logging is cluster scoped + Name: l.Name, + }, + }) + } + } + return +} + func min(a, b int) int { if a < b { return a diff --git a/docs/configuration/crds/v1beta1/_index.md b/docs/configuration/crds/v1beta1/_index.md index c34ea5e99..b7dbe3738 100644 --- a/docs/configuration/crds/v1beta1/_index.md +++ b/docs/configuration/crds/v1beta1/_index.md @@ -18,7 +18,7 @@ For more information please click on the name | **[](conversion/)** | | v1beta1 | | **[FlowSpec](flow_types/)** | FlowSpec is the Kubernetes spec for Flows | v1beta1 | | **[FluentbitSpec](fluentbit_types/)** | FluentbitSpec defines the desired state of FluentbitAgent | v1beta1 | -| **[FluentdSpec](fluentd_types/)** | FluentdSpec defines the desired state of Fluentd | v1beta1 | +| **[Fluent](fluentd_types/)** | FluentdConfig is a reference to the desired Fluentd state | v1beta1 | | **[Logging](logging_types/)** | Logging system configuration | v1beta1 | | **[LoggingRouteSpec](loggingroute_types/)** | LoggingRouteSpec defines the desired state of LoggingRoute | v1beta1 | | **[_hugoNodeAgent](node_agent_types/)** | | v1beta1 | diff --git a/docs/configuration/crds/v1beta1/fluentd_types.md b/docs/configuration/crds/v1beta1/fluentd_types.md index 4553801aa..13aedb2c7 100644 --- a/docs/configuration/crds/v1beta1/fluentd_types.md +++ b/docs/configuration/crds/v1beta1/fluentd_types.md @@ -170,6 +170,60 @@ Fluentd port inside the container (24240 by default). The headless service port +--- +title: FluentdConfig +weight: 200 +generated_file: true +--- + +## FluentdConfig + +FluentdConfig + +### (metav1.TypeMeta, required) {#fluentdconfig-} + + +### metadata (metav1.ObjectMeta, optional) {#fluentdconfig-metadata} + + +### spec (FluentdSpec, optional) {#fluentdconfig-spec} + + +### status (FluentdConfigStatus, optional) {#fluentdconfig-status} + + + +## FluentdConfigStatus + +FluentdConfigStatus + +### active (*bool, optional) {#fluentdconfigstatus-active} + + +### logging (string, optional) {#fluentdconfigstatus-logging} + + +### problems ([]string, optional) {#fluentdconfigstatus-problems} + + +### problemsCount (int, optional) {#fluentdconfigstatus-problemscount} + + + +## FluentdConfigList + +FluentdConfigList + +### (metav1.TypeMeta, required) {#fluentdconfiglist-} + + +### metadata (metav1.ListMeta, optional) {#fluentdconfiglist-metadata} + + +### items ([]FluentdConfig, required) {#fluentdconfiglist-items} + + + ## FluentOutLogrotate ### age (string, optional) {#fluentoutlogrotate-age} diff --git a/docs/configuration/crds/v1beta1/logging_types.md b/docs/configuration/crds/v1beta1/logging_types.md index 5e007a2e7..caa158fb3 100644 --- a/docs/configuration/crds/v1beta1/logging_types.md +++ b/docs/configuration/crds/v1beta1/logging_types.md @@ -127,6 +127,11 @@ LoggingStatus defines the observed state of Logging Result of the config check. Under normal conditions there is a single item in the map with a bool value. +### fluentdConfigName (string, optional) {#loggingstatus-fluentdconfigname} + +Name of the matched detached fluentd configuration object + + ### problems ([]string, optional) {#loggingstatus-problems} Problems with the logging resource diff --git a/docs/standalone-aggregator-config.md b/docs/standalone-aggregator-config.md new file mode 100644 index 000000000..2bdb7490e --- /dev/null +++ b/docs/standalone-aggregator-config.md @@ -0,0 +1,120 @@ +## Standalone Fluentd config + +The standalone `FluentdConfig` is a namespaced resource that allows the configuration of the Fluentd / SyslogNG +aggregator component in the control namespace separately from the Logging resource. + +The primary benefit of this behaviour is that it enables a multi-tenant model, where tenant owners are responsible +for operating their own aggregator, while the Logging resource is in control of the central operations team. +For more information about the multi-tenancy model where the collector is capable of routing logs based on namespaces +to individual aggregators and where aggregators are fully isolated, please see [Multi-tenancy](multi-tenancy.md) + +Traditional configuration of fluentd within the logging resource: +``` +apiVersion: logging.banzaicloud.io/v1beta1 +kind: Logging +metadata: + name: example +spec: + controlNamespace: logging + fluentd: + scaling: + replicas: 2 +``` + +The alternative configuration is as follows: +``` +apiVersion: logging.banzaicloud.io/v1beta1 +kind: Logging +metadata: + name: example +spec: + controlNamespace: logging +--- +apiVersion: logging.banzaicloud.io/v1beta1 +kind: FluentdConfig +metadata: + name: example + namespace: logging +spec: + scaling: + replicas: 2 +``` + +### Schema and migration + +The schema for `FluentdConfig.spec` is the same as it was withing `Logging.spec.fluentd`, so the migration should be a trivial lift and shift +exercise. + +### Restrictions and status + +There can only be one active `FluentdConfig` for a single `Logging` resource at a time. The controller will make +sure to register the active `FluentdConfig` resource into the `Logging` resource's status under `fluentdConfigName`, +while registering the `Logging` resource name under `logging` in the `FluentdConfig` resource's status. + +``` +kubectl get logging example -o jsonpath='{.status}' | jq . +{ + "configCheckResults": { + "ac2d4553": true + }, + "fluentdConfigName": "example" +} +``` + +``` +kubectl get fluentdconfig example -o jsonpath='{.status}' | jq . +{ + "active": true, + "logging": "example" +} +``` + +If there is a conflict, then the controller will add a problem to both resources so that both operations and tenant users can be aware of it. +For example add another `FluentdConfig` resource on top of the existing one: + +``` +apiVersion: logging.banzaicloud.io/v1beta1 +kind: FluentdConfig +metadata: + name: example2 + namespace: logging +spec: {} +``` + +The first `FluentdConfig` should be left intact, while the second one should have the following status: +``` +kubectl get fluentdconfig example2 -o jsonpath='{.status}' | jq . +{ + "active": false, + "problems": [ + "logging already has a detached fluentd configuration, remove excess configuration objects" + ], + "problemsCount": 1 +} +``` + +The `Logging` resource will also highlight the issue +``` +kubectl get logging example -o jsonpath='{.status}' | jq . +{ + "configCheckResults": { + "ac2d4553": true + }, + "fluentdConfigName": "example", + "problems": [ + "multiple fluentd configurations found, couldn't associate it with logging" + ], + "problemsCount": 1 +} +``` + +Once the extra `FluentdConfig` resource is removed the `Logging` resource status should return back to normal: +``` +kubectl get logging example -o jsonpath='{.status}' | jq . +{ + "configCheckResults": { + "ac2d4553": true + }, + "fluentdConfigName": "example" +} +``` diff --git a/e2e/common/cond/conditions.go b/e2e/common/cond/conditions.go index 1e65dfc38..5fed3f2c2 100644 --- a/e2e/common/cond/conditions.go +++ b/e2e/common/cond/conditions.go @@ -18,6 +18,9 @@ import ( "context" "testing" + "github.com/cisco-open/operator-tools/pkg/utils" + "github.com/kube-logging/logging-operator/e2e/common" + "github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "sigs.k8s.io/controller-runtime/pkg/client" @@ -82,3 +85,48 @@ func ResourceShouldBePresent(t *testing.T, cl client.Reader, obj client.Object) return false } } +func CheckFluentdStatus(t *testing.T, c *common.Cluster, ctx *context.Context, fluentd *v1beta1.FluentdConfig, loggingName string) bool { + fluentdInstanceName := fluentd.Name + cluster := *c + + if len(fluentd.Status.Problems) != 0 { + common.RequireNoError(t, cluster.GetClient().Get(*ctx, utils.ObjectKeyFromObjectMeta(fluentd), fluentd)) + t.Logf("%s should have 0 problems, problems=%v", fluentdInstanceName, fluentd.Status.Problems) + return false + } + if fluentd.Status.Logging != loggingName { + common.RequireNoError(t, cluster.GetClient().Get(*ctx, utils.ObjectKeyFromObjectMeta(fluentd), fluentd)) + t.Logf("%s should have it's logging field filled, found: %s, expect:%s", fluentdInstanceName, fluentd.Status.Logging, loggingName) + return false + } + if !*fluentd.Status.Active { + common.RequireNoError(t, cluster.GetClient().Get(*ctx, utils.ObjectKeyFromObjectMeta(fluentd), fluentd)) + t.Logf("%s should have it's active field set as true, found: %v", fluentdInstanceName, *fluentd.Status.Active) + return false + } + + return true +} + +func CheckExcessFluentdStatus(t *testing.T, c *common.Cluster, ctx *context.Context, fluentd *v1beta1.FluentdConfig) bool { + fluentdInstanceName := fluentd.Name + cluster := *c + + if len(fluentd.Status.Problems) == 0 { + common.RequireNoError(t, cluster.GetClient().Get(*ctx, utils.ObjectKeyFromObjectMeta(fluentd), fluentd)) + t.Logf("%s should have it's problems field filled", fluentdInstanceName) + return false + } + if fluentd.Status.Logging != "" { + common.RequireNoError(t, cluster.GetClient().Get(*ctx, utils.ObjectKeyFromObjectMeta(fluentd), fluentd)) + t.Logf("%s should have it's logging field empty, found: %s", fluentdInstanceName, fluentd.Status.Logging) + return false + } + if *fluentd.Status.Active { + common.RequireNoError(t, cluster.GetClient().Get(*ctx, utils.ObjectKeyFromObjectMeta(fluentd), fluentd)) + t.Logf("%s should have it's active field set as false, found: %v", fluentdInstanceName, *fluentd.Status.Active) + return false + } + + return true +} diff --git a/e2e/fluentd-aggregator-detached-multiple-failures/fluentd_aggregator_detached_multiple_failures_test.go b/e2e/fluentd-aggregator-detached-multiple-failures/fluentd_aggregator_detached_multiple_failures_test.go new file mode 100644 index 000000000..720be791f --- /dev/null +++ b/e2e/fluentd-aggregator-detached-multiple-failures/fluentd_aggregator_detached_multiple_failures_test.go @@ -0,0 +1,226 @@ +// Copyright © 2021 Cisco Systems, Inc. and/or its affiliates +// +// 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 fluentd_aggregator + +import ( + "context" + "fmt" + "os" + "path/filepath" + "testing" + "time" + + "github.com/cisco-open/operator-tools/pkg/utils" + "github.com/stretchr/testify/require" + appsv1 "k8s.io/api/apps/v1" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/cluster" + + "github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1" + "github.com/kube-logging/logging-operator/pkg/sdk/logging/model/output" + + "github.com/kube-logging/logging-operator/e2e/common" + "github.com/kube-logging/logging-operator/e2e/common/cond" + "github.com/kube-logging/logging-operator/e2e/common/setup" +) + +var TestTempDirUnnamed string + +func init() { + var ok bool + TestTempDirUnnamed, ok = os.LookupEnv("PROJECT_DIR") + if !ok { + TestTempDirUnnamed = "../.." + } + TestTempDirUnnamed = filepath.Join(TestTempDirUnnamed, "build/_test") + err := os.MkdirAll(TestTempDirUnnamed, os.FileMode(0755)) + if err != nil { + panic(err) + } +} + +func TestFluentdAggregator_detached_multiple_failure(t *testing.T) { + common.Initialize(t) + ns := "testing-1" + releaseNameOverride := "e2e" + testTag := "test.fluentd_aggregator_multiworker_multiple_detached_failure" + outputName := "test-output" + flowName := "test-flow" + common.WithCluster("fluentd-1-detached-unnamed", t, func(t *testing.T, c common.Cluster) { + setup.LoggingOperator(t, c, setup.LoggingOperatorOptionFunc(func(options *setup.LoggingOperatorOptions) { + options.Namespace = ns + options.NameOverride = releaseNameOverride + })) + + ctx := context.Background() + + logging := v1beta1.Logging{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fluentd-aggregator-multiworker-test", + Namespace: ns, + }, + Spec: v1beta1.LoggingSpec{ + EnableRecreateWorkloadOnImmutableFieldChange: true, + ControlNamespace: ns, + FluentbitSpec: &v1beta1.FluentbitSpec{ + Network: &v1beta1.FluentbitNetwork{ + Keepalive: utils.BoolPointer(false), + }, + }, + }, + } + common.RequireNoError(t, c.GetClient().Create(ctx, &logging)) + + fluentd1 := v1beta1.FluentdConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "not-to-be-used-fluentd-1", + Namespace: ns, + }, + Spec: v1beta1.FluentdSpec{ + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("200M"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("250m"), + corev1.ResourceMemory: resource.MustParse("50M"), + }, + }, + BufferVolumeMetrics: &v1beta1.Metrics{}, + Scaling: &v1beta1.FluentdScaling{ + Replicas: 1, + Drain: v1beta1.FluentdDrainConfig{ + Enabled: true, + }, + }, + Workers: 2, + }, + } + common.RequireNoError(t, c.GetClient().Create(ctx, &fluentd1)) + + fluentd2 := v1beta1.FluentdConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "not-to-be-used-fluentd-2", + Namespace: ns, + }, + Spec: v1beta1.FluentdSpec{ + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("200M"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("250m"), + corev1.ResourceMemory: resource.MustParse("50M"), + }, + }, + BufferVolumeMetrics: &v1beta1.Metrics{}, + Scaling: &v1beta1.FluentdScaling{ + Replicas: 1, + Drain: v1beta1.FluentdDrainConfig{ + Enabled: true, + }, + }, + Workers: 2, + }, + } + common.RequireNoError(t, c.GetClient().Create(ctx, &fluentd2)) + + t.Logf("fluentd is: %v", fluentd1) + tags := "time" + output := v1beta1.Output{ + ObjectMeta: metav1.ObjectMeta{ + Name: outputName, + Namespace: ns, + }, + Spec: v1beta1.OutputSpec{ + HTTPOutput: &output.HTTPOutputConfig{ + Endpoint: fmt.Sprintf("http://%s-test-receiver:8080/%s", releaseNameOverride, testTag), + ContentType: "application/json", + Buffer: &output.Buffer{ + Type: "file", + Tags: &tags, + Timekey: "1s", + TimekeyWait: "0s", + }, + }, + }, + } + + producerLabels := map[string]string{ + "my-unique-label": "log-producer", + } + + common.RequireNoError(t, c.GetClient().Create(ctx, &output)) + flow := v1beta1.Flow{ + ObjectMeta: metav1.ObjectMeta{ + Name: flowName, + Namespace: ns, + }, + Spec: v1beta1.FlowSpec{ + Match: []v1beta1.Match{ + { + Select: &v1beta1.Select{ + Labels: producerLabels, + }, + }, + }, + LocalOutputRefs: []string{output.Name}, + }, + } + common.RequireNoError(t, c.GetClient().Create(ctx, &flow)) + + go setup.LogProducer(t, c.GetClient(), setup.LogProducerOptionFunc(func(options *setup.LogProducerOptions) { + options.Namespace = ns + options.Labels = producerLabels + })) + + require.Eventually(t, func() bool { + if rv := cond.CheckExcessFluentdStatus(t, &c, &ctx, &fluentd1); !rv { + return false + } + if rv := cond.CheckExcessFluentdStatus(t, &c, &ctx, &fluentd2); !rv { + return false + } + return true + }, 5*time.Minute, 3*time.Second) + + }, func(t *testing.T, c common.Cluster) error { + path := filepath.Join(TestTempDirUnnamed, fmt.Sprintf("cluster-%s.log", t.Name())) + t.Logf("Printing cluster logs to %s", path) + return c.PrintLogs(common.PrintLogConfig{ + Namespaces: []string{ns, "default"}, + FilePath: path, + Limit: 100 * 1000, + }) + }, func(o *cluster.Options) { + if o.Scheme == nil { + o.Scheme = runtime.NewScheme() + } + common.RequireNoError(t, v1beta1.AddToScheme(o.Scheme)) + common.RequireNoError(t, apiextensionsv1.AddToScheme(o.Scheme)) + common.RequireNoError(t, appsv1.AddToScheme(o.Scheme)) + common.RequireNoError(t, batchv1.AddToScheme(o.Scheme)) + common.RequireNoError(t, corev1.AddToScheme(o.Scheme)) + common.RequireNoError(t, rbacv1.AddToScheme(o.Scheme)) + }) +} diff --git a/e2e/fluentd-aggregator-detached/fluentd_aggregator_detached_test.go b/e2e/fluentd-aggregator-detached/fluentd_aggregator_detached_test.go new file mode 100644 index 000000000..9b7e0a211 --- /dev/null +++ b/e2e/fluentd-aggregator-detached/fluentd_aggregator_detached_test.go @@ -0,0 +1,273 @@ +// Copyright © 2021 Cisco Systems, Inc. and/or its affiliates +// +// 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 fluentd_aggregator + +import ( + "context" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/cisco-open/operator-tools/pkg/utils" + "github.com/stretchr/testify/require" + appsv1 "k8s.io/api/apps/v1" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/cluster" + + "github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1" + "github.com/kube-logging/logging-operator/pkg/sdk/logging/model/output" + + "github.com/kube-logging/logging-operator/e2e/common" + "github.com/kube-logging/logging-operator/e2e/common/cond" + "github.com/kube-logging/logging-operator/e2e/common/setup" +) + +var TestTempDir string + +func init() { + var ok bool + TestTempDir, ok = os.LookupEnv("PROJECT_DIR") + if !ok { + TestTempDir = "../.." + } + TestTempDir = filepath.Join(TestTempDir, "build/_test") + err := os.MkdirAll(TestTempDir, os.FileMode(0755)) + if err != nil { + panic(err) + } +} + +func TestFluentdAggregator_detached_MultiWorker(t *testing.T) { + common.Initialize(t) + ns := "testing-1" + releaseNameOverride := "e2e" + testTag := "test.fluentd_aggregator_multiworker_detached" + outputName := "test-output" + flowName := "test-flow" + common.WithCluster("fluentd-1-detached", t, func(t *testing.T, c common.Cluster) { + setup.LoggingOperator(t, c, setup.LoggingOperatorOptionFunc(func(options *setup.LoggingOperatorOptions) { + options.Namespace = ns + options.NameOverride = releaseNameOverride + })) + + ctx := context.Background() + + logging := v1beta1.Logging{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fluentd-aggregator-multiworker-test", + Namespace: ns, + }, + Spec: v1beta1.LoggingSpec{ + EnableRecreateWorkloadOnImmutableFieldChange: true, + ControlNamespace: ns, + FluentbitSpec: &v1beta1.FluentbitSpec{ + Network: &v1beta1.FluentbitNetwork{ + Keepalive: utils.BoolPointer(false), + }, + }, + }, + } + common.RequireNoError(t, c.GetClient().Create(ctx, &logging)) + + fluentd := v1beta1.FluentdConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "detached-fluentd", + Namespace: ns, + }, + Spec: v1beta1.FluentdSpec{ + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("200M"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("250m"), + corev1.ResourceMemory: resource.MustParse("50M"), + }, + }, + BufferVolumeMetrics: &v1beta1.Metrics{}, + Scaling: &v1beta1.FluentdScaling{ + Replicas: 1, + Drain: v1beta1.FluentdDrainConfig{ + Enabled: true, + }, + }, + Workers: 2, + }, + } + + common.RequireNoError(t, c.GetClient().Create(ctx, &fluentd)) + t.Logf("fluentd is: %v", fluentd) + + excessFluentd := v1beta1.FluentdConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: "excess-fluentd", + Namespace: ns, + }, + Spec: v1beta1.FluentdSpec{ + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("200M"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("250m"), + corev1.ResourceMemory: resource.MustParse("50M"), + }, + }, + BufferVolumeMetrics: &v1beta1.Metrics{}, + Scaling: &v1beta1.FluentdScaling{ + Replicas: 1, + Drain: v1beta1.FluentdDrainConfig{ + Enabled: true, + }, + }, + }, + } + tags := "time" + output := v1beta1.Output{ + ObjectMeta: metav1.ObjectMeta{ + Name: outputName, + Namespace: ns, + }, + Spec: v1beta1.OutputSpec{ + HTTPOutput: &output.HTTPOutputConfig{ + Endpoint: fmt.Sprintf("http://%s-test-receiver:8080/%s", releaseNameOverride, testTag), + ContentType: "application/json", + Buffer: &output.Buffer{ + Type: "file", + Tags: &tags, + Timekey: "1s", + TimekeyWait: "0s", + }, + }, + }, + } + + producerLabels := map[string]string{ + "my-unique-label": "log-producer", + } + + common.RequireNoError(t, c.GetClient().Create(ctx, &output)) + flow := v1beta1.Flow{ + ObjectMeta: metav1.ObjectMeta{ + Name: flowName, + Namespace: ns, + }, + Spec: v1beta1.FlowSpec{ + Match: []v1beta1.Match{ + { + Select: &v1beta1.Select{ + Labels: producerLabels, + }, + }, + }, + LocalOutputRefs: []string{output.Name}, + }, + } + common.RequireNoError(t, c.GetClient().Create(ctx, &flow)) + + aggregatorLabels := map[string]string{ + "app.kubernetes.io/name": "fluentd", + "app.kubernetes.io/component": "fluentd", + } + operatorLabels := map[string]string{ + "app.kubernetes.io/name": releaseNameOverride, + } + + go setup.LogProducer(t, c.GetClient(), setup.LogProducerOptionFunc(func(options *setup.LogProducerOptions) { + options.Namespace = ns + options.Labels = producerLabels + })) + + require.Eventually(t, func() bool { + if operatorRunning := cond.AnyPodShouldBeRunning(t, c.GetClient(), client.MatchingLabels(operatorLabels))(); !operatorRunning { + t.Log("waiting for the operator") + return false + } + if producerRunning := cond.AnyPodShouldBeRunning(t, c.GetClient(), client.MatchingLabels(producerLabels))(); !producerRunning { + t.Log("waiting for the producer") + return false + } + if aggregatorRunning := cond.AnyPodShouldBeRunning(t, c.GetClient(), client.MatchingLabels(aggregatorLabels)); !aggregatorRunning() { + t.Log("waiting for the aggregator") + return false + } + if len(logging.Status.FluentdConfigName) == 0 || logging.Status.FluentdConfigName != fluentd.Name { + common.RequireNoError(t, c.GetClient().Get(ctx, utils.ObjectKeyFromObjectMeta(&logging), &logging)) + t.Logf("logging should use the detached fluentd configuration (name=%s), found: %v", fluentd.Name, logging.Status.FluentdConfigName) + return false + } + if isValid := cond.CheckFluentdStatus(t, &c, &ctx, &fluentd, logging.Name); !isValid { + t.Log("checking detached fluentd status") + return false + } + var detachedFluentds v1beta1.FluentdConfigList + common.RequireNoError(t, c.GetClient().List(ctx, &detachedFluentds)) + if len(detachedFluentds.Items) != 2 { + // Add a new detached fluentd that is not going to be used + common.RequireNoError(t, c.GetClient().Create(ctx, &excessFluentd)) + t.Log("creating excess detached fluentd") + return false + } else if isValid := cond.CheckExcessFluentdStatus(t, &c, &ctx, &excessFluentd); !isValid && len(detachedFluentds.Items) == 2 { + t.Log("checking excess detached fluentd status") + common.RequireNoError(t, c.GetClient().Get(ctx, utils.ObjectKeyFromObjectMeta(&excessFluentd), &excessFluentd)) + return false + } + + cmd := common.CmdEnv(exec.Command("kubectl", + "logs", + "-n", ns, + "-l", fmt.Sprintf("app.kubernetes.io/name=%s-test-receiver", releaseNameOverride)), c) + rawOut, err := cmd.Output() + if err != nil { + t.Logf("failed to get log consumer logs: %v", err) + return false + } + t.Logf("log consumer logs: %s", rawOut) + return strings.Contains(string(rawOut), testTag) + }, 5*time.Minute, 3*time.Second) + + }, func(t *testing.T, c common.Cluster) error { + path := filepath.Join(TestTempDir, fmt.Sprintf("cluster-%s.log", t.Name())) + t.Logf("Printing cluster logs to %s", path) + return c.PrintLogs(common.PrintLogConfig{ + Namespaces: []string{ns, "default"}, + FilePath: path, + Limit: 100 * 1000, + }) + }, func(o *cluster.Options) { + if o.Scheme == nil { + o.Scheme = runtime.NewScheme() + } + common.RequireNoError(t, v1beta1.AddToScheme(o.Scheme)) + common.RequireNoError(t, apiextensionsv1.AddToScheme(o.Scheme)) + common.RequireNoError(t, appsv1.AddToScheme(o.Scheme)) + common.RequireNoError(t, batchv1.AddToScheme(o.Scheme)) + common.RequireNoError(t, corev1.AddToScheme(o.Scheme)) + common.RequireNoError(t, rbacv1.AddToScheme(o.Scheme)) + }) +} diff --git a/pkg/resources/fluentbit/configsecret.go b/pkg/resources/fluentbit/configsecret.go index 3bee53e53..d7aef9ab8 100644 --- a/pkg/resources/fluentbit/configsecret.go +++ b/pkg/resources/fluentbit/configsecret.go @@ -184,7 +184,6 @@ func newFluentbitNetwork(network v1beta1.FluentbitNetwork) (result FluentbitNetw func (r *Reconciler) configSecret() (runtime.Object, reconciler.DesiredState, error) { ctx := context.TODO() - if r.fluentbitSpec.CustomConfigSecret != "" { return &corev1.Secret{ ObjectMeta: r.FluentbitObjectMeta(fluentBitSecretConfigName), @@ -239,7 +238,7 @@ func (r *Reconciler) configSecret() (runtime.Object, reconciler.DesiredState, er } } - if r.Logging.Spec.FluentdSpec != nil { + if r.fluentdSpec != nil { fluentbitTargetHost := r.fluentbitSpec.TargetHost if fluentbitTargetHost == "" { fluentbitTargetHost = aggregatorEndpoint(r.Logging, fluentd.ServiceName) @@ -366,7 +365,7 @@ func (r *Reconciler) configSecret() (runtime.Object, reconciler.DesiredState, er for _, a := range r.loggingRoutes { tenants = append(tenants, a.Status.Tenants...) } - if err := r.configureOutputsForTenants(ctx, tenants, &input); err != nil { + if err := r.configureOutputsForTenants(ctx, tenants, &input, r.fluentdSpec); err != nil { return nil, nil, errors.WrapIf(err, "configuring outputs for target tenants") } } else { diff --git a/pkg/resources/fluentbit/fluentbit.go b/pkg/resources/fluentbit/fluentbit.go index 159e37f57..f736b62f8 100644 --- a/pkg/resources/fluentbit/fluentbit.go +++ b/pkg/resources/fluentbit/fluentbit.go @@ -90,6 +90,7 @@ type Reconciler struct { resourceReconciler *reconciler.GenericResourceReconciler logger logr.Logger Logging *v1beta1.Logging + fluentdSpec *v1beta1.FluentdSpec configs map[string][]byte fluentbitSpec *v1beta1.FluentbitSpec loggingDataProvider loggingdataprovider.LoggingDataProvider @@ -101,6 +102,7 @@ type Reconciler struct { func New(client client.Client, logger logr.Logger, logging *v1beta1.Logging, + fluentdSpec *v1beta1.FluentdSpec, opts reconciler.ReconcilerOpts, fluentbitSpec *v1beta1.FluentbitSpec, loggingDataProvider loggingdataprovider.LoggingDataProvider, @@ -108,6 +110,7 @@ func New(client client.Client, loggingRoutes []v1beta1.LoggingRoute) *Reconciler { return &Reconciler{ Logging: logging, + fluentdSpec: fluentdSpec, logger: logger, resourceReconciler: reconciler.NewGenericReconciler(client, logger.WithName("reconciler"), opts), fluentbitSpec: fluentbitSpec, diff --git a/pkg/resources/fluentbit/tenants.go b/pkg/resources/fluentbit/tenants.go index b65fa2aff..5800f7c56 100644 --- a/pkg/resources/fluentbit/tenants.go +++ b/pkg/resources/fluentbit/tenants.go @@ -88,7 +88,7 @@ func FindTenants(ctx context.Context, target metav1.LabelSelector, reader client return tenants, nil } -func (r *Reconciler) configureOutputsForTenants(ctx context.Context, tenants []v1beta1.Tenant, input *fluentBitConfig) error { +func (r *Reconciler) configureOutputsForTenants(ctx context.Context, tenants []v1beta1.Tenant, input *fluentBitConfig, fluentdSpec *v1beta1.FluentdSpec) error { var errs error for _, t := range tenants { allNamespaces := len(t.Namespaces) == 0 @@ -100,7 +100,7 @@ func (r *Reconciler) configureOutputsForTenants(ctx context.Context, tenants []v if err := r.resourceReconciler.Client.Get(ctx, types.NamespacedName{Name: t.Name}, logging); err != nil { return errors.WrapIf(err, "getting logging resource") } - if logging.Spec.FluentdSpec != nil { + if fluentdSpec != nil { if input.FluentForwardOutput == nil { input.FluentForwardOutput = &fluentForwardOutputConfig{} } diff --git a/pkg/resources/fluentd/appconfigmap.go b/pkg/resources/fluentd/appconfigmap.go index 67a2e319c..1dac41421 100644 --- a/pkg/resources/fluentd/appconfigmap.go +++ b/pkg/resources/fluentd/appconfigmap.go @@ -43,7 +43,7 @@ type ConfigCheckResult struct { func (r *Reconciler) appConfigSecret() (runtime.Object, reconciler.DesiredState, error) { data := make(map[string][]byte) - if r.Logging.Spec.FluentdSpec.CompressConfigFile { + if r.fluentdSpec.CompressConfigFile { AppConfigKeyCompress := AppConfigKey + ".gz" data[AppConfigKeyCompress] = compression.CompressString(*r.config, r.Log) } else { @@ -65,9 +65,9 @@ func (r *Reconciler) configHash() (string, error) { return fmt.Sprintf("%x", hasher.Sum32()), nil } -func (r *Reconciler) hasConfigCheckPod(ctx context.Context, hashKey string) (bool, error) { +func (r *Reconciler) hasConfigCheckPod(ctx context.Context, hashKey string, fluentdSpec v1beta1.FluentdSpec) (bool, error) { var err error - pod := r.newCheckPod(hashKey) + pod := r.newCheckPod(hashKey, fluentdSpec) p := &corev1.Pod{} err = r.Client.Get(ctx, client.ObjectKeyFromObject(pod), p) @@ -98,12 +98,12 @@ func (r *Reconciler) configCheck(ctx context.Context) (*ConfigCheckResult, error return nil, err } - checkSecret, err := r.newCheckSecret(hashKey) + checkSecret, err := r.newCheckSecret(hashKey, *r.fluentdSpec) if err != nil { return nil, err } configcheck.WithHashLabel(checkSecret, hashKey) - checkSecretAppConfig, err := r.newCheckSecretAppConfig(hashKey) + checkSecretAppConfig, err := r.newCheckSecretAppConfig(hashKey, *r.fluentdSpec) if err != nil { return nil, err } @@ -138,7 +138,7 @@ func (r *Reconciler) configCheck(ctx context.Context) (*ConfigCheckResult, error return res, errors.WrapIf(err, "failed to find output secret for fluentd configcheck") } - pod := r.newCheckPod(hashKey) + pod := r.newCheckPod(hashKey, *r.fluentdSpec) configcheck.WithHashLabel(pod, hashKey) existingPods := &corev1.PodList{} @@ -202,12 +202,12 @@ func (r *Reconciler) configCheck(ctx context.Context) (*ConfigCheckResult, error return &ConfigCheckResult{}, nil } -func (r *Reconciler) newCheckSecret(hashKey string) (*corev1.Secret, error) { - data, err := r.generateConfigSecret() +func (r *Reconciler) newCheckSecret(hashKey string, fluentdSpec v1beta1.FluentdSpec) (*corev1.Secret, error) { + data, err := r.generateConfigSecret(fluentdSpec) if err != nil { return nil, err } - if r.Logging.Spec.FluentdSpec.CompressConfigFile { + if fluentdSpec.CompressConfigFile { ConfigCheckKeyCompress := ConfigCheckKey + ".gz" data[ConfigCheckKeyCompress] = compression.CompressString(*r.config, r.Log) } else { @@ -220,10 +220,10 @@ func (r *Reconciler) newCheckSecret(hashKey string) (*corev1.Secret, error) { }, nil } -func (r *Reconciler) newCheckSecretAppConfig(hashKey string) (*corev1.Secret, error) { +func (r *Reconciler) newCheckSecretAppConfig(hashKey string, fluentdSpec v1beta1.FluentdSpec) (*corev1.Secret, error) { data := make(map[string][]byte) - if r.Logging.Spec.FluentdSpec.CompressConfigFile { + if fluentdSpec.CompressConfigFile { ConfigCheckKeyCompress := ConfigCheckKey + ".gz" data[ConfigCheckKeyCompress] = compression.CompressString(*r.config, r.Log) } else { @@ -247,43 +247,43 @@ func (r *Reconciler) newCheckOutputSecret(hashKey string) (*corev1.Secret, error return nil, errors.New("output secret is invalid, unable to create output secret for config check") } -func (r *Reconciler) newCheckPod(hashKey string) *corev1.Pod { +func (r *Reconciler) newCheckPod(hashKey string, fluentdSpec v1beta1.FluentdSpec) *corev1.Pod { - volumes := r.volumesCheckPod(hashKey) - container := r.containerCheckPod(hashKey) - initContainer := r.initContainerCheckPod() + volumes := r.volumesCheckPod(hashKey, fluentdSpec) + container := r.containerCheckPod(hashKey, fluentdSpec) + initContainer := r.initContainerCheckPod(fluentdSpec) pod := &corev1.Pod{ ObjectMeta: r.configCheckPodObjectMeta(fmt.Sprintf("fluentd-configcheck-%s", hashKey), ComponentConfigCheck), Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, ServiceAccountName: r.getServiceAccount(), - NodeSelector: r.Logging.Spec.FluentdSpec.NodeSelector, - Tolerations: r.Logging.Spec.FluentdSpec.Tolerations, - Affinity: r.Logging.Spec.FluentdSpec.Affinity, - PriorityClassName: r.Logging.Spec.FluentdSpec.PodPriorityClassName, + NodeSelector: fluentdSpec.NodeSelector, + Tolerations: fluentdSpec.Tolerations, + Affinity: fluentdSpec.Affinity, + PriorityClassName: fluentdSpec.PodPriorityClassName, SecurityContext: &corev1.PodSecurityContext{ - RunAsNonRoot: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.RunAsNonRoot, - FSGroup: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.FSGroup, - RunAsUser: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.RunAsUser, - RunAsGroup: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.RunAsGroup, - SeccompProfile: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.SeccompProfile, + RunAsNonRoot: fluentdSpec.Security.PodSecurityContext.RunAsNonRoot, + FSGroup: fluentdSpec.Security.PodSecurityContext.FSGroup, + RunAsUser: fluentdSpec.Security.PodSecurityContext.RunAsUser, + RunAsGroup: fluentdSpec.Security.PodSecurityContext.RunAsGroup, + SeccompProfile: fluentdSpec.Security.PodSecurityContext.SeccompProfile, }, Volumes: volumes, - ImagePullSecrets: r.Logging.Spec.FluentdSpec.Image.ImagePullSecrets, + ImagePullSecrets: fluentdSpec.Image.ImagePullSecrets, InitContainers: initContainer, Containers: container, }, } - if r.Logging.Spec.FluentdSpec.ConfigCheckAnnotations != nil { - pod.Annotations = r.Logging.Spec.FluentdSpec.ConfigCheckAnnotations + if fluentdSpec.ConfigCheckAnnotations != nil { + pod.Annotations = fluentdSpec.ConfigCheckAnnotations } - if r.Logging.Spec.FluentdSpec.TLS.Enabled { + if fluentdSpec.TLS.Enabled { tlsVolume := corev1.Volume{ Name: "fluentd-tls", VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: r.Logging.Spec.FluentdSpec.TLS.SecretName, + SecretName: fluentdSpec.TLS.SecretName, }, }, } @@ -294,7 +294,7 @@ func (r *Reconciler) newCheckPod(hashKey string) *corev1.Pod { } pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, volumeMount) } - for _, n := range r.Logging.Spec.FluentdSpec.ExtraVolumes { + for _, n := range fluentdSpec.ExtraVolumes { if err := n.ApplyVolumeForPodSpec(&pod.Spec); err != nil { r.Log.Error(err, "Fluentd Config check pod extraVolume attachment failed.") } @@ -303,7 +303,7 @@ func (r *Reconciler) newCheckPod(hashKey string) *corev1.Pod { return pod } -func (r *Reconciler) volumesCheckPod(hashKey string) (v []corev1.Volume) { +func (r *Reconciler) volumesCheckPod(hashKey string, fluentdSpec v1beta1.FluentdSpec) (v []corev1.Volume) { v = []corev1.Volume{ { Name: "config", @@ -323,7 +323,7 @@ func (r *Reconciler) volumesCheckPod(hashKey string) (v []corev1.Volume) { }, } - if r.Logging.Spec.FluentdSpec.CompressConfigFile { + if fluentdSpec.CompressConfigFile { v = append(v, corev1.Volume{ Name: "app-config", VolumeSource: corev1.VolumeSource{ @@ -352,7 +352,7 @@ func (r *Reconciler) volumesCheckPod(hashKey string) (v []corev1.Volume) { return v } -func (r *Reconciler) containerCheckPod(hashKey string) []corev1.Container { +func (r *Reconciler) containerCheckPod(hashKey string, fluentdSpec v1beta1.FluentdSpec) []corev1.Container { var containerArgs []string switch r.Logging.Spec.ConfigCheck.Strategy { @@ -372,15 +372,15 @@ func (r *Reconciler) containerCheckPod(hashKey string) []corev1.Container { } } - containerArgs = append(containerArgs, r.Logging.Spec.FluentdSpec.ExtraArgs...) + containerArgs = append(containerArgs, fluentdSpec.ExtraArgs...) container := []corev1.Container{ { Name: "fluentd", - Image: r.Logging.Spec.FluentdSpec.Image.RepositoryWithTag(), - ImagePullPolicy: corev1.PullPolicy(r.Logging.Spec.FluentdSpec.Image.PullPolicy), + Image: fluentdSpec.Image.RepositoryWithTag(), + ImagePullPolicy: corev1.PullPolicy(fluentdSpec.Image.PullPolicy), Args: containerArgs, - Env: r.Logging.Spec.FluentdSpec.EnvVars, + Env: fluentdSpec.EnvVars, VolumeMounts: []corev1.VolumeMount{ { Name: "config", @@ -395,23 +395,23 @@ func (r *Reconciler) containerCheckPod(hashKey string) []corev1.Container { MountPath: OutputSecretPath, }, }, - SecurityContext: r.Logging.Spec.FluentdSpec.Security.SecurityContext, - Resources: r.Logging.Spec.FluentdSpec.ConfigCheckResources, + SecurityContext: fluentdSpec.Security.SecurityContext, + Resources: fluentdSpec.ConfigCheckResources, }, } return container } -func (r *Reconciler) initContainerCheckPod() []corev1.Container { +func (r *Reconciler) initContainerCheckPod(fluentdSpec v1beta1.FluentdSpec) []corev1.Container { var initContainer []corev1.Container - if r.Logging.Spec.FluentdSpec.CompressConfigFile { + if fluentdSpec.CompressConfigFile { initContainer = []corev1.Container{ { Name: "config-reloader", - Image: r.Logging.Spec.FluentdSpec.ConfigReloaderImage.RepositoryWithTag(), - ImagePullPolicy: corev1.PullPolicy(r.Logging.Spec.FluentdSpec.Image.PullPolicy), - Resources: r.Logging.Spec.FluentdSpec.ConfigReloaderResources, + Image: fluentdSpec.ConfigReloaderImage.RepositoryWithTag(), + ImagePullPolicy: corev1.PullPolicy(fluentdSpec.Image.PullPolicy), + Resources: fluentdSpec.ConfigReloaderResources, Args: []string{ "--init-mode=true", "--volume-dir-archive=/tmp/archive", diff --git a/pkg/resources/fluentd/buffervolumeprometheusrules.go b/pkg/resources/fluentd/buffervolumeprometheusrules.go index 5339be695..46898970c 100644 --- a/pkg/resources/fluentd/buffervolumeprometheusrules.go +++ b/pkg/resources/fluentd/buffervolumeprometheusrules.go @@ -31,7 +31,7 @@ func (r *Reconciler) bufferVolumePrometheusRules() (runtime.Object, reconciler.D } state := reconciler.StateAbsent - if r.Logging.Spec.FluentdSpec.BufferVolumeMetrics != nil && r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.PrometheusRules { + if r.fluentdSpec.BufferVolumeMetrics != nil && r.fluentdSpec.BufferVolumeMetrics.PrometheusRules { nsJobLabel := fmt.Sprintf(`job="%s", namespace="%s"`, obj.Name, obj.Namespace) state = reconciler.StatePresent const ruleGroupName = "fluentd-buffervolume" diff --git a/pkg/resources/fluentd/configsecret.go b/pkg/resources/fluentd/configsecret.go index 8332d8b68..ff7e63550 100644 --- a/pkg/resources/fluentd/configsecret.go +++ b/pkg/resources/fluentd/configsecret.go @@ -21,6 +21,7 @@ import ( "emperror.dev/errors" "github.com/cisco-open/operator-tools/pkg/reconciler" + "github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" ) @@ -52,24 +53,24 @@ func generateConfig(input fluentdConfig) (string, error) { return output.String(), nil } -func (r *Reconciler) generateConfigSecret() (map[string][]byte, error) { +func (r *Reconciler) generateConfigSecret(fluentdSpec v1beta1.FluentdSpec) (map[string][]byte, error) { input := fluentdConfig{ - IgnoreSameLogInterval: r.Logging.Spec.FluentdSpec.IgnoreSameLogInterval, - IgnoreRepeatedLogInterval: r.Logging.Spec.FluentdSpec.IgnoreRepeatedLogInterval, - EnableMsgpackTimeSupport: r.Logging.Spec.FluentdSpec.EnableMsgpackTimeSupport, - Workers: r.Logging.Spec.FluentdSpec.Workers, - LogLevel: r.Logging.Spec.FluentdSpec.LogLevel, + IgnoreSameLogInterval: fluentdSpec.IgnoreSameLogInterval, + IgnoreRepeatedLogInterval: fluentdSpec.IgnoreRepeatedLogInterval, + EnableMsgpackTimeSupport: fluentdSpec.EnableMsgpackTimeSupport, + Workers: fluentdSpec.Workers, + LogLevel: fluentdSpec.LogLevel, } - input.RootDir = r.Logging.Spec.FluentdSpec.RootDir + input.RootDir = fluentdSpec.RootDir if input.RootDir == "" { input.RootDir = bufferPath } - if r.Logging.Spec.FluentdSpec.Metrics != nil { + if fluentdSpec.Metrics != nil { input.Monitor.Enabled = true - input.Monitor.Port = r.Logging.Spec.FluentdSpec.Metrics.Port - input.Monitor.Path = r.Logging.Spec.FluentdSpec.Metrics.Path + input.Monitor.Port = fluentdSpec.Metrics.Port + input.Monitor.Path = fluentdSpec.Metrics.Path } inputConfig, err := generateConfig(input) @@ -86,11 +87,11 @@ func (r *Reconciler) generateConfigSecret() (map[string][]byte, error) { } func (r *Reconciler) secretConfig() (runtime.Object, reconciler.DesiredState, error) { - configMap, err := r.generateConfigSecret() + configMap, err := r.generateConfigSecret(*r.fluentdSpec) if err != nil { return nil, nil, err } - configMap["fluentlog.conf"] = []byte(fmt.Sprintf(fluentLog, r.Logging.Spec.FluentdSpec.FluentLogDestination)) + configMap["fluentlog.conf"] = []byte(fmt.Sprintf(fluentLog, r.fluentdSpec.FluentLogDestination)) configs := &corev1.Secret{ ObjectMeta: r.FluentdObjectMeta(SecretConfigName, ComponentFluentd), Data: configMap, diff --git a/pkg/resources/fluentd/dataprovider.go b/pkg/resources/fluentd/dataprovider.go index b933a2346..ccba81e86 100644 --- a/pkg/resources/fluentd/dataprovider.go +++ b/pkg/resources/fluentd/dataprovider.go @@ -25,21 +25,23 @@ import ( ) type DataProvider struct { - client client.Client - logging *v1beta1.Logging + client client.Client + logging *v1beta1.Logging + fluentdSpec *v1beta1.FluentdSpec } -func NewDataProvider(client client.Client, logging *v1beta1.Logging) *DataProvider { +func NewDataProvider(client client.Client, logging *v1beta1.Logging, fluentdSpec *v1beta1.FluentdSpec) *DataProvider { return &DataProvider{ - client: client, - logging: logging, + client: client, + logging: logging, + fluentdSpec: fluentdSpec, } } func (p *DataProvider) GetReplicaCount(ctx context.Context) (*int32, error) { - if p.logging.Spec.FluentdSpec != nil { + if p.fluentdSpec != nil { sts := &v1.StatefulSet{} - om := p.logging.FluentdObjectMeta(StatefulSetName, ComponentFluentd) + om := p.logging.FluentdObjectMeta(StatefulSetName, ComponentFluentd, *p.fluentdSpec) err := p.client.Get(ctx, types.NamespacedName{Namespace: om.Namespace, Name: om.Name}, sts) if err != nil { return nil, errors.WrapIf(client.IgnoreNotFound(err), "getting fluentd statefulset") diff --git a/pkg/resources/fluentd/drainjob.go b/pkg/resources/fluentd/drainjob.go index 4eb09ce78..7d7a29c7b 100644 --- a/pkg/resources/fluentd/drainjob.go +++ b/pkg/resources/fluentd/drainjob.go @@ -24,24 +24,24 @@ import ( "github.com/kube-logging/logging-operator/pkg/sdk/logging/api/v1beta1" ) -func (r *Reconciler) drainerJobFor(pvc corev1.PersistentVolumeClaim) (*batchv1.Job, error) { - bufVolName := r.Logging.QualifiedName(r.Logging.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeSource.ClaimName) +func (r *Reconciler) drainerJobFor(pvc corev1.PersistentVolumeClaim, fluentdSpec v1beta1.FluentdSpec) (*batchv1.Job, error) { + bufVolName := r.Logging.QualifiedName(fluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeSource.ClaimName) - fluentdContainer := fluentContainer(withoutFluentOutLogrotate(r.Logging.Spec.FluentdSpec)) + fluentdContainer := fluentContainer(withoutFluentOutLogrotate(&fluentdSpec)) fluentdContainer.VolumeMounts = append(fluentdContainer.VolumeMounts, corev1.VolumeMount{ Name: bufVolName, MountPath: bufferPath, }) containers := []corev1.Container{ fluentdContainer, - drainWatchContainer(&r.Logging.Spec.FluentdSpec.Scaling.Drain, bufVolName), + drainWatchContainer(&fluentdSpec.Scaling.Drain, bufVolName), } if c := r.bufferMetricsSidecarContainer(); c != nil { containers = append(containers, *c) } var initContainers []corev1.Container - if i := generateInitContainer(r.Logging.Spec.FluentdSpec); i != nil { + if i := generateInitContainer(fluentdSpec); i != nil { initContainers = append(initContainers, *i) } if c := r.tmpDirHackContainer(); c != nil { @@ -51,26 +51,26 @@ func (r *Reconciler) drainerJobFor(pvc corev1.PersistentVolumeClaim) (*batchv1.J spec := batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: r.getDrainerLabels(), - Annotations: r.Logging.Spec.FluentdSpec.Scaling.Drain.Annotations, + Labels: r.getDrainerLabels(fluentdSpec), + Annotations: fluentdSpec.Scaling.Drain.Annotations, }, Spec: corev1.PodSpec{ Volumes: r.generateVolume(), ServiceAccountName: r.getServiceAccount(), - ImagePullSecrets: r.Logging.Spec.FluentdSpec.Image.ImagePullSecrets, + ImagePullSecrets: fluentdSpec.Image.ImagePullSecrets, InitContainers: initContainers, Containers: containers, - NodeSelector: r.Logging.Spec.FluentdSpec.NodeSelector, - Tolerations: r.Logging.Spec.FluentdSpec.Tolerations, - Affinity: r.Logging.Spec.FluentdSpec.Affinity, - TopologySpreadConstraints: r.Logging.Spec.FluentdSpec.TopologySpreadConstraints, - PriorityClassName: r.Logging.Spec.FluentdSpec.PodPriorityClassName, + NodeSelector: fluentdSpec.NodeSelector, + Tolerations: fluentdSpec.Tolerations, + Affinity: fluentdSpec.Affinity, + TopologySpreadConstraints: fluentdSpec.TopologySpreadConstraints, + PriorityClassName: fluentdSpec.PodPriorityClassName, SecurityContext: &corev1.PodSecurityContext{ - RunAsNonRoot: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.RunAsNonRoot, - FSGroup: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.FSGroup, - RunAsUser: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.RunAsUser, - RunAsGroup: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.RunAsGroup, - SeccompProfile: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.SeccompProfile, + RunAsNonRoot: fluentdSpec.Security.PodSecurityContext.RunAsNonRoot, + FSGroup: fluentdSpec.Security.PodSecurityContext.FSGroup, + RunAsUser: fluentdSpec.Security.PodSecurityContext.RunAsUser, + RunAsGroup: fluentdSpec.Security.PodSecurityContext.RunAsGroup, + SeccompProfile: fluentdSpec.Security.PodSecurityContext.SeccompProfile, }, RestartPolicy: corev1.RestartPolicyNever, }, @@ -85,7 +85,7 @@ func (r *Reconciler) drainerJobFor(pvc corev1.PersistentVolumeClaim) (*batchv1.J }, }, }) - for _, n := range r.Logging.Spec.FluentdSpec.ExtraVolumes { + for _, n := range fluentdSpec.ExtraVolumes { if err := n.ApplyVolumeForPodSpec(&spec.Template.Spec); err != nil { return nil, err } @@ -129,10 +129,10 @@ func withoutFluentOutLogrotate(spec *v1beta1.FluentdSpec) *v1beta1.FluentdSpec { return res } -func (r *Reconciler) getDrainerLabels() map[string]string { - labels := r.Logging.GetFluentdLabels(ComponentDrainer) +func (r *Reconciler) getDrainerLabels(fluentdSpec v1beta1.FluentdSpec) map[string]string { + labels := r.Logging.GetFluentdLabels(ComponentDrainer, fluentdSpec) - for key, value := range r.Logging.Spec.FluentdSpec.Scaling.Drain.Labels { + for key, value := range fluentdSpec.Scaling.Drain.Labels { labels[key] = value } diff --git a/pkg/resources/fluentd/fluentd.go b/pkg/resources/fluentd/fluentd.go index d9a4ca65f..3ca335536 100644 --- a/pkg/resources/fluentd/fluentd.go +++ b/pkg/resources/fluentd/fluentd.go @@ -68,7 +68,8 @@ const ( // Reconciler holds info what resource to reconcile type Reconciler struct { - Logging *v1beta1.Logging + Logging *v1beta1.Logging + fluentdSpec *v1beta1.FluentdSpec *reconciler.GenericResourceReconciler config *string secrets *secret.MountSecrets @@ -82,17 +83,39 @@ type Desire struct { BeforeUpdateHook func(runtime.Object) (reconciler.DesiredState, error) } +func GetFluentd(ctx context.Context, Client client.Client, log logr.Logger, controlNamespace string) *v1beta1.FluentdConfig { + fluentdList := v1beta1.FluentdConfigList{} + // Detached fluentd must be in the `control namespace` + nsOpt := client.InNamespace(controlNamespace) + + if err := Client.List(ctx, &fluentdList, nsOpt); err != nil { + log.Error(err, "listing fluentd configuration") + return nil + } + + if len(fluentdList.Items) > 1 { + log.Error(errors.New("multiple fluentd configurations found"), fmt.Sprintf("number of configurations: %d", len(fluentdList.Items))) + return nil + } + + if len(fluentdList.Items) == 1 { + return &fluentdList.Items[0] + } + return nil +} + func (r *Reconciler) getServiceAccount() string { - if r.Logging.Spec.FluentdSpec.Security.ServiceAccount != "" { - return r.Logging.Spec.FluentdSpec.Security.ServiceAccount + if r.fluentdSpec.Security.ServiceAccount != "" { + return r.fluentdSpec.Security.ServiceAccount } return r.Logging.QualifiedName(defaultServiceAccountName) } func New(client client.Client, log logr.Logger, - logging *v1beta1.Logging, config *string, secrets *secret.MountSecrets, opts reconciler.ReconcilerOpts) *Reconciler { + logging *v1beta1.Logging, fluentdSpec *v1beta1.FluentdSpec, config *string, secrets *secret.MountSecrets, opts reconciler.ReconcilerOpts) *Reconciler { return &Reconciler{ Logging: logging, + fluentdSpec: fluentdSpec, GenericResourceReconciler: reconciler.NewGenericReconciler(client, log, opts), config: config, secrets: secrets, @@ -140,7 +163,7 @@ func (r *Reconciler) Reconcile(ctx context.Context) (*reconcile.Result, error) { // Fail when the current config is invalid if result, ok := r.Logging.Status.ConfigCheckResults[hash]; ok && !result { - if hasPod, err := r.hasConfigCheckPod(ctx, hash); hasPod { + if hasPod, err := r.hasConfigCheckPod(ctx, hash, *r.fluentdSpec); hasPod { return nil, errors.WrapIf(err, "current config is invalid") } // clean the status so that we can rerun the check @@ -265,13 +288,13 @@ func (r *Reconciler) statusUpdate(ctx context.Context, patchBase client.Patch, r } func (r *Reconciler) reconcileDrain(ctx context.Context) (*reconcile.Result, error) { - if r.Logging.Spec.FluentdSpec.DisablePvc || !r.Logging.Spec.FluentdSpec.Scaling.Drain.Enabled { + if r.fluentdSpec.DisablePvc || !r.fluentdSpec.Scaling.Drain.Enabled { r.Log.Info("fluentd buffer draining is disabled") return nil, nil } nsOpt := client.InNamespace(r.Logging.Spec.ControlNamespace) - fluentdLabelSet := r.Logging.GetFluentdLabels(ComponentFluentd) + fluentdLabelSet := r.Logging.GetFluentdLabels(ComponentFluentd, *r.fluentdSpec) var pvcList corev1.PersistentVolumeClaimList if err := r.Client.List(ctx, &pvcList, nsOpt, @@ -286,7 +309,7 @@ func (r *Reconciler) reconcileDrain(ctx context.Context) (*reconcile.Result, err return nil, errors.WrapIf(err, "listing StatefulSet pods") } - bufVolName := r.Logging.QualifiedName(r.Logging.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeSource.ClaimName) + bufVolName := r.Logging.QualifiedName(r.fluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeSource.ClaimName) pvcsInUse := make(map[string]bool) for _, pod := range stsPods.Items { @@ -295,7 +318,7 @@ func (r *Reconciler) reconcileDrain(ctx context.Context) (*reconcile.Result, err } } - replicaCount, err := NewDataProvider(r.Client, r.Logging).GetReplicaCount(ctx) + replicaCount, err := NewDataProvider(r.Client, r.Logging, r.fluentdSpec).GetReplicaCount(ctx) if err != nil { return nil, errors.WrapIf(err, "get replica count for fluentd") } @@ -306,7 +329,7 @@ func (r *Reconciler) reconcileDrain(ctx context.Context) (*reconcile.Result, err } var jobList batchv1.JobList - if err := r.Client.List(ctx, &jobList, nsOpt, client.MatchingLabels(r.Logging.GetFluentdLabels(ComponentDrainer))); err != nil { + if err := r.Client.List(ctx, &jobList, nsOpt, client.MatchingLabels(r.Logging.GetFluentdLabels(ComponentDrainer, *r.fluentdSpec))); err != nil { return nil, errors.WrapIf(err, "listing buffer drainer jobs") } @@ -350,7 +373,7 @@ func (r *Reconciler) reconcileDrain(ctx context.Context) (*reconcile.Result, err continue } - if r.Logging.Spec.FluentdSpec.Scaling.Drain.DeleteVolume { + if r.fluentdSpec.Scaling.Drain.DeleteVolume { if err := client.IgnoreNotFound(r.Client.Delete(ctx, &pvc, client.PropagationPolicy(v1.DeletePropagationBackground))); err != nil { cr.CombineErr(errors.WrapIfWithDetails(err, "deleting drained PVC", "pvc", pvc.Name)) continue @@ -397,7 +420,7 @@ func (r *Reconciler) reconcileDrain(ctx context.Context) (*reconcile.Result, err continue } - if job, err := r.drainerJobFor(pvc); err != nil { + if job, err := r.drainerJobFor(pvc, *r.fluentdSpec); err != nil { cr.CombineErr(errors.WrapIf(err, "assembling drainer job")) } else { cr.Combine(r.ReconcileResource(job, reconciler.StatePresent)) diff --git a/pkg/resources/fluentd/meta.go b/pkg/resources/fluentd/meta.go index a5a26b7d2..9833736ce 100644 --- a/pkg/resources/fluentd/meta.go +++ b/pkg/resources/fluentd/meta.go @@ -24,7 +24,7 @@ func (r *Reconciler) FluentdObjectMeta(name, component string) metav1.ObjectMeta o := metav1.ObjectMeta{ Name: r.Logging.QualifiedName(name), Namespace: r.Logging.Spec.ControlNamespace, - Labels: r.Logging.GetFluentdLabels(component), + Labels: r.Logging.GetFluentdLabels(component, *r.fluentdSpec), OwnerReferences: []metav1.OwnerReference{ { APIVersion: r.Logging.APIVersion, @@ -42,7 +42,7 @@ func (r *Reconciler) FluentdObjectMeta(name, component string) metav1.ObjectMeta func (r *Reconciler) FluentdObjectMetaClusterScope(name, component string) metav1.ObjectMeta { o := metav1.ObjectMeta{ Name: r.Logging.QualifiedName(name), - Labels: r.Logging.GetFluentdLabels(component), + Labels: r.Logging.GetFluentdLabels(component, *r.fluentdSpec), OwnerReferences: []metav1.OwnerReference{ { APIVersion: r.Logging.APIVersion, diff --git a/pkg/resources/fluentd/placeholderpod.go b/pkg/resources/fluentd/placeholderpod.go index 89b90d9e9..0d07e1f55 100644 --- a/pkg/resources/fluentd/placeholderpod.go +++ b/pkg/resources/fluentd/placeholderpod.go @@ -28,14 +28,14 @@ func (r *Reconciler) placeholderPodFor(pvc corev1.PersistentVolumeClaim) *corev1 Containers: []corev1.Container{ { Name: "pause", - Image: r.Logging.Spec.FluentdSpec.Scaling.Drain.PauseImage.RepositoryWithTag(), - ImagePullPolicy: corev1.PullPolicy(r.Logging.Spec.FluentdSpec.Scaling.Drain.PauseImage.PullPolicy), + Image: r.fluentdSpec.Scaling.Drain.PauseImage.RepositoryWithTag(), + ImagePullPolicy: corev1.PullPolicy(r.fluentdSpec.Scaling.Drain.PauseImage.PullPolicy), }, }, - NodeSelector: r.Logging.Spec.FluentdSpec.NodeSelector, - Tolerations: r.Logging.Spec.FluentdSpec.Tolerations, - Affinity: r.Logging.Spec.FluentdSpec.Affinity, - PriorityClassName: r.Logging.Spec.FluentdSpec.PodPriorityClassName, + NodeSelector: r.fluentdSpec.NodeSelector, + Tolerations: r.fluentdSpec.Tolerations, + Affinity: r.fluentdSpec.Affinity, + PriorityClassName: r.fluentdSpec.PodPriorityClassName, RestartPolicy: corev1.RestartPolicyNever, TerminationGracePeriodSeconds: utils.IntPointer64(0), // terminate immediately }, diff --git a/pkg/resources/fluentd/prometheusrules.go b/pkg/resources/fluentd/prometheusrules.go index acd04fa41..32b1ee6f1 100644 --- a/pkg/resources/fluentd/prometheusrules.go +++ b/pkg/resources/fluentd/prometheusrules.go @@ -18,11 +18,10 @@ import ( "fmt" "github.com/cisco-open/operator-tools/pkg/reconciler" + prometheus_operator "github.com/kube-logging/logging-operator/pkg/resources/prometheus-operator" v1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" - - "github.com/kube-logging/logging-operator/pkg/resources/prometheus-operator" ) func (r *Reconciler) prometheusRules() (runtime.Object, reconciler.DesiredState, error) { @@ -31,7 +30,7 @@ func (r *Reconciler) prometheusRules() (runtime.Object, reconciler.DesiredState, } state := reconciler.StateAbsent - if r.Logging.Spec.FluentdSpec.Metrics != nil && r.Logging.Spec.FluentdSpec.Metrics.PrometheusRules { + if r.fluentdSpec.Metrics != nil && r.fluentdSpec.Metrics.PrometheusRules { nsJobLabel := fmt.Sprintf(`job="%s", namespace="%s"`, obj.Name, obj.Namespace) state = reconciler.StatePresent const ruleGroupName = "fluentd" diff --git a/pkg/resources/fluentd/psp.go b/pkg/resources/fluentd/psp.go index 3528dd6f9..85cebfa25 100644 --- a/pkg/resources/fluentd/psp.go +++ b/pkg/resources/fluentd/psp.go @@ -24,7 +24,7 @@ import ( ) func (r *Reconciler) clusterPodSecurityPolicy() (runtime.Object, reconciler.DesiredState, error) { - if r.Logging.Spec.FluentdSpec.Security.PodSecurityPolicyCreate { + if r.fluentdSpec.Security.PodSecurityPolicyCreate { return &policyv1beta1.PodSecurityPolicy{ ObjectMeta: r.FluentdObjectMetaClusterScope(PodSecurityPolicyName, ComponentFluentd), Spec: policyv1beta1.PodSecurityPolicySpec{ @@ -59,7 +59,7 @@ func (r *Reconciler) clusterPodSecurityPolicy() (runtime.Object, reconciler.Desi } func (r *Reconciler) pspRole() (runtime.Object, reconciler.DesiredState, error) { - if *r.Logging.Spec.FluentdSpec.Security.RoleBasedAccessControlCreate && r.Logging.Spec.FluentdSpec.Security.PodSecurityPolicyCreate { + if *r.fluentdSpec.Security.RoleBasedAccessControlCreate && r.fluentdSpec.Security.PodSecurityPolicyCreate { return &rbacv1.Role{ ObjectMeta: r.FluentdObjectMeta(roleName+"-psp", ComponentFluentd), Rules: []rbacv1.PolicyRule{ @@ -78,7 +78,7 @@ func (r *Reconciler) pspRole() (runtime.Object, reconciler.DesiredState, error) } func (r *Reconciler) pspRoleBinding() (runtime.Object, reconciler.DesiredState, error) { - if *r.Logging.Spec.FluentdSpec.Security.RoleBasedAccessControlCreate && r.Logging.Spec.FluentdSpec.Security.PodSecurityPolicyCreate { + if *r.fluentdSpec.Security.RoleBasedAccessControlCreate && r.fluentdSpec.Security.PodSecurityPolicyCreate { return &rbacv1.RoleBinding{ ObjectMeta: r.FluentdObjectMeta(roleBindingName+"-psp", ComponentFluentd), RoleRef: rbacv1.RoleRef{ diff --git a/pkg/resources/fluentd/rbac.go b/pkg/resources/fluentd/rbac.go index f00b5075a..5dfb8703d 100644 --- a/pkg/resources/fluentd/rbac.go +++ b/pkg/resources/fluentd/rbac.go @@ -24,7 +24,7 @@ import ( ) func (r *Reconciler) role() (runtime.Object, reconciler.DesiredState, error) { - if *r.Logging.Spec.FluentdSpec.Security.RoleBasedAccessControlCreate { + if *r.fluentdSpec.Security.RoleBasedAccessControlCreate { return &rbacv1.Role{ ObjectMeta: r.FluentdObjectMeta(roleName, ComponentFluentd), Rules: []rbacv1.PolicyRule{ @@ -42,7 +42,7 @@ func (r *Reconciler) role() (runtime.Object, reconciler.DesiredState, error) { } func (r *Reconciler) roleBinding() (runtime.Object, reconciler.DesiredState, error) { - if *r.Logging.Spec.FluentdSpec.Security.RoleBasedAccessControlCreate { + if *r.fluentdSpec.Security.RoleBasedAccessControlCreate { return &rbacv1.RoleBinding{ ObjectMeta: r.FluentdObjectMeta(roleBindingName, ComponentFluentd), RoleRef: rbacv1.RoleRef{ @@ -74,7 +74,7 @@ func (r *Reconciler) isEnhanceK8sFilter() bool { } func (r *Reconciler) clusterRole() (runtime.Object, reconciler.DesiredState, error) { - if *r.Logging.Spec.FluentdSpec.Security.RoleBasedAccessControlCreate && r.isEnhanceK8sFilter() { + if *r.fluentdSpec.Security.RoleBasedAccessControlCreate && r.isEnhanceK8sFilter() { return &rbacv1.ClusterRole{ ObjectMeta: r.FluentdObjectMetaClusterScope(clusterRoleName, ComponentFluentd), Rules: []rbacv1.PolicyRule{ @@ -115,7 +115,7 @@ func (r *Reconciler) clusterRole() (runtime.Object, reconciler.DesiredState, err } func (r *Reconciler) clusterRoleBinding() (runtime.Object, reconciler.DesiredState, error) { - if *r.Logging.Spec.FluentdSpec.Security.RoleBasedAccessControlCreate && r.isEnhanceK8sFilter() { + if *r.fluentdSpec.Security.RoleBasedAccessControlCreate && r.isEnhanceK8sFilter() { return &rbacv1.ClusterRoleBinding{ ObjectMeta: r.FluentdObjectMetaClusterScope(clusterRoleBindingName, ComponentFluentd), RoleRef: rbacv1.RoleRef{ @@ -138,11 +138,11 @@ func (r *Reconciler) clusterRoleBinding() (runtime.Object, reconciler.DesiredSta } func (r *Reconciler) serviceAccount() (runtime.Object, reconciler.DesiredState, error) { - if *r.Logging.Spec.FluentdSpec.Security.RoleBasedAccessControlCreate && r.Logging.Spec.FluentdSpec.Security.ServiceAccount == "" { + if *r.fluentdSpec.Security.RoleBasedAccessControlCreate && r.fluentdSpec.Security.ServiceAccount == "" { desired := &corev1.ServiceAccount{ ObjectMeta: r.FluentdObjectMeta(defaultServiceAccountName, ComponentFluentd), } - err := merge.Merge(desired, r.Logging.Spec.FluentdSpec.ServiceAccountOverrides) + err := merge.Merge(desired, r.fluentdSpec.ServiceAccountOverrides) if err != nil { return desired, reconciler.StatePresent, errors.WrapIf(err, "unable to merge overrides to base object") } diff --git a/pkg/resources/fluentd/service.go b/pkg/resources/fluentd/service.go index 73659d9e4..c89465add 100644 --- a/pkg/resources/fluentd/service.go +++ b/pkg/resources/fluentd/service.go @@ -33,16 +33,16 @@ func (r *Reconciler) service() (runtime.Object, reconciler.DesiredState, error) Name: "tcp-fluentd", Protocol: corev1.ProtocolTCP, Port: ServicePort, - TargetPort: intstr.IntOrString{IntVal: r.Logging.Spec.FluentdSpec.Port}, + TargetPort: intstr.IntOrString{IntVal: r.fluentdSpec.Port}, }, { Name: "udp-fluentd", Protocol: corev1.ProtocolUDP, Port: ServicePort, - TargetPort: intstr.IntOrString{IntVal: r.Logging.Spec.FluentdSpec.Port}, + TargetPort: intstr.IntOrString{IntVal: r.fluentdSpec.Port}, }, }, - Selector: r.Logging.GetFluentdLabels(ComponentFluentd), + Selector: r.Logging.GetFluentdLabels(ComponentFluentd, *r.fluentdSpec), Type: corev1.ServiceTypeClusterIP, }, } @@ -60,7 +60,7 @@ func (r *Reconciler) service() (runtime.Object, reconciler.DesiredState, error) } func (r *Reconciler) serviceMetrics() (runtime.Object, reconciler.DesiredState, error) { - if r.Logging.Spec.FluentdSpec.Metrics != nil { + if r.fluentdSpec.Metrics != nil { return &corev1.Service{ ObjectMeta: r.FluentdObjectMeta(ServiceName+"-metrics", ComponentFluentd), Spec: corev1.ServiceSpec{ @@ -68,11 +68,11 @@ func (r *Reconciler) serviceMetrics() (runtime.Object, reconciler.DesiredState, { Protocol: corev1.ProtocolTCP, Name: "http-metrics", - Port: r.Logging.Spec.FluentdSpec.Metrics.Port, - TargetPort: intstr.IntOrString{IntVal: r.Logging.Spec.FluentdSpec.Metrics.Port}, + Port: r.fluentdSpec.Metrics.Port, + TargetPort: intstr.IntOrString{IntVal: r.fluentdSpec.Metrics.Port}, }, }, - Selector: r.Logging.GetFluentdLabels(ComponentFluentd), + Selector: r.Logging.GetFluentdLabels(ComponentFluentd, *r.fluentdSpec), Type: corev1.ServiceTypeClusterIP, ClusterIP: "None", }, @@ -85,10 +85,10 @@ func (r *Reconciler) serviceMetrics() (runtime.Object, reconciler.DesiredState, func (r *Reconciler) monitorServiceMetrics() (runtime.Object, reconciler.DesiredState, error) { var SampleLimit uint64 = 0 - if r.Logging.Spec.FluentdSpec.Metrics != nil && r.Logging.Spec.FluentdSpec.Metrics.ServiceMonitor { + if r.fluentdSpec.Metrics != nil && r.fluentdSpec.Metrics.ServiceMonitor { objectMetadata := r.FluentdObjectMeta(ServiceName+"-metrics", ComponentFluentd) - if r.Logging.Spec.FluentdSpec.Metrics.ServiceMonitorConfig.AdditionalLabels != nil { - for k, v := range r.Logging.Spec.FluentdSpec.Metrics.ServiceMonitorConfig.AdditionalLabels { + if r.fluentdSpec.Metrics.ServiceMonitorConfig.AdditionalLabels != nil { + for k, v := range r.fluentdSpec.Metrics.ServiceMonitorConfig.AdditionalLabels { objectMetadata.Labels[k] = v } } @@ -101,16 +101,16 @@ func (r *Reconciler) monitorServiceMetrics() (runtime.Object, reconciler.Desired PodTargetLabels: nil, Endpoints: []v1.Endpoint{{ Port: "http-metrics", - Path: r.Logging.GetFluentdMetricsPath(), - Interval: v1.Duration(r.Logging.Spec.FluentdSpec.Metrics.Interval), - ScrapeTimeout: v1.Duration(r.Logging.Spec.FluentdSpec.Metrics.Timeout), - HonorLabels: r.Logging.Spec.FluentdSpec.Metrics.ServiceMonitorConfig.HonorLabels, - RelabelConfigs: r.Logging.Spec.FluentdSpec.Metrics.ServiceMonitorConfig.Relabelings, - MetricRelabelConfigs: r.Logging.Spec.FluentdSpec.Metrics.ServiceMonitorConfig.MetricsRelabelings, - Scheme: r.Logging.Spec.FluentdSpec.Metrics.ServiceMonitorConfig.Scheme, - TLSConfig: r.Logging.Spec.FluentdSpec.Metrics.ServiceMonitorConfig.TLSConfig, + Path: r.fluentdSpec.GetFluentdMetricsPath(), + Interval: v1.Duration(r.fluentdSpec.Metrics.Interval), + ScrapeTimeout: v1.Duration(r.fluentdSpec.Metrics.Timeout), + HonorLabels: r.fluentdSpec.Metrics.ServiceMonitorConfig.HonorLabels, + RelabelConfigs: r.fluentdSpec.Metrics.ServiceMonitorConfig.Relabelings, + MetricRelabelConfigs: r.fluentdSpec.Metrics.ServiceMonitorConfig.MetricsRelabelings, + Scheme: r.fluentdSpec.Metrics.ServiceMonitorConfig.Scheme, + TLSConfig: r.fluentdSpec.Metrics.ServiceMonitorConfig.TLSConfig, }}, - Selector: v12.LabelSelector{MatchLabels: r.Logging.GetFluentdLabels(ComponentFluentd)}, + Selector: v12.LabelSelector{MatchLabels: r.Logging.GetFluentdLabels(ComponentFluentd, *r.fluentdSpec)}, NamespaceSelector: v1.NamespaceSelector{MatchNames: []string{r.Logging.Spec.ControlNamespace}}, SampleLimit: &SampleLimit, }, @@ -123,10 +123,10 @@ func (r *Reconciler) monitorServiceMetrics() (runtime.Object, reconciler.Desired } func (r *Reconciler) serviceBufferMetrics() (runtime.Object, reconciler.DesiredState, error) { - if r.Logging.Spec.FluentdSpec.BufferVolumeMetrics != nil { + if r.fluentdSpec.BufferVolumeMetrics != nil { port := int32(defaultBufferVolumeMetricsPort) - if r.Logging.Spec.FluentdSpec.BufferVolumeMetrics != nil && r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.Port != 0 { - port = r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.Port + if r.fluentdSpec.BufferVolumeMetrics != nil && r.fluentdSpec.BufferVolumeMetrics.Port != 0 { + port = r.fluentdSpec.BufferVolumeMetrics.Port } return &corev1.Service{ @@ -140,7 +140,7 @@ func (r *Reconciler) serviceBufferMetrics() (runtime.Object, reconciler.DesiredS TargetPort: intstr.IntOrString{IntVal: port}, }, }, - Selector: r.Logging.GetFluentdLabels(ComponentFluentd), + Selector: r.Logging.GetFluentdLabels(ComponentFluentd, *r.fluentdSpec), Type: corev1.ServiceTypeClusterIP, ClusterIP: "None", }, @@ -153,10 +153,10 @@ func (r *Reconciler) serviceBufferMetrics() (runtime.Object, reconciler.DesiredS func (r *Reconciler) monitorBufferServiceMetrics() (runtime.Object, reconciler.DesiredState, error) { var SampleLimit uint64 = 0 - if r.Logging.Spec.FluentdSpec.BufferVolumeMetrics != nil && r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.ServiceMonitor { + if r.fluentdSpec.BufferVolumeMetrics != nil && r.fluentdSpec.BufferVolumeMetrics.ServiceMonitor { objectMetadata := r.FluentdObjectMeta(ServiceName+"-buffer-metrics", ComponentFluentd) - if r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.AdditionalLabels != nil { - for k, v := range r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.AdditionalLabels { + if r.fluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.AdditionalLabels != nil { + for k, v := range r.fluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.AdditionalLabels { objectMetadata.Labels[k] = v } } @@ -168,16 +168,16 @@ func (r *Reconciler) monitorBufferServiceMetrics() (runtime.Object, reconciler.D PodTargetLabels: nil, Endpoints: []v1.Endpoint{{ Port: "buffer-metrics", - Path: r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.Path, - Interval: v1.Duration(r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.Interval), - ScrapeTimeout: v1.Duration(r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.Timeout), - HonorLabels: r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.HonorLabels, - RelabelConfigs: r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.Relabelings, - MetricRelabelConfigs: r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.MetricsRelabelings, - Scheme: r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.Scheme, - TLSConfig: r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.TLSConfig, + Path: r.fluentdSpec.BufferVolumeMetrics.Path, + Interval: v1.Duration(r.fluentdSpec.BufferVolumeMetrics.Interval), + ScrapeTimeout: v1.Duration(r.fluentdSpec.BufferVolumeMetrics.Timeout), + HonorLabels: r.fluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.HonorLabels, + RelabelConfigs: r.fluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.Relabelings, + MetricRelabelConfigs: r.fluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.MetricsRelabelings, + Scheme: r.fluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.Scheme, + TLSConfig: r.fluentdSpec.BufferVolumeMetrics.ServiceMonitorConfig.TLSConfig, }}, - Selector: v12.LabelSelector{MatchLabels: r.Logging.GetFluentdLabels(ComponentFluentd)}, + Selector: v12.LabelSelector{MatchLabels: r.Logging.GetFluentdLabels(ComponentFluentd, *r.fluentdSpec)}, NamespaceSelector: v1.NamespaceSelector{MatchNames: []string{r.Logging.Spec.ControlNamespace}}, SampleLimit: &SampleLimit, }, @@ -199,17 +199,17 @@ func (r *Reconciler) headlessService() (runtime.Object, reconciler.DesiredState, Protocol: corev1.ProtocolTCP, // This port should match the containerport and targetPort will be automatically set to the same // https://github.com/kubernetes/kubernetes/issues/20488 - Port: r.Logging.Spec.FluentdSpec.Port, + Port: r.fluentdSpec.Port, }, { Name: "udp-fluentd", Protocol: corev1.ProtocolUDP, // This port should match the containerport and targetPort will be automatically set to the same // https://github.com/kubernetes/kubernetes/issues/20488 - Port: r.Logging.Spec.FluentdSpec.Port, + Port: r.fluentdSpec.Port, }, }, - Selector: r.Logging.GetFluentdLabels(ComponentFluentd), + Selector: r.Logging.GetFluentdLabels(ComponentFluentd, *r.fluentdSpec), Type: corev1.ServiceTypeClusterIP, ClusterIP: corev1.ClusterIPNone, }, diff --git a/pkg/resources/fluentd/statefulset.go b/pkg/resources/fluentd/statefulset.go index ab1c313db..ddb1c1b6b 100644 --- a/pkg/resources/fluentd/statefulset.go +++ b/pkg/resources/fluentd/statefulset.go @@ -32,23 +32,23 @@ import ( func (r *Reconciler) statefulset() (runtime.Object, reconciler.DesiredState, error) { spec := r.statefulsetSpec() - r.Logging.Spec.FluentdSpec.BufferStorageVolume.WithDefaultHostPath( + r.fluentdSpec.BufferStorageVolume.WithDefaultHostPath( fmt.Sprintf(v1beta1.HostPath, r.Logging.Name, r.Logging.QualifiedName(v1beta1.DefaultFluentdBufferStorageVolumeName)), ) - if !r.Logging.Spec.FluentdSpec.DisablePvc { - err := r.Logging.Spec.FluentdSpec.BufferStorageVolume.ApplyPVCForStatefulSet(containerName, bufferPath, spec, func(name string) metav1.ObjectMeta { + if !r.fluentdSpec.DisablePvc { + err := r.fluentdSpec.BufferStorageVolume.ApplyPVCForStatefulSet(containerName, bufferPath, spec, func(name string) metav1.ObjectMeta { return r.FluentdObjectMeta(name, ComponentFluentd) }) if err != nil { return nil, reconciler.StatePresent, err } } else { - err := r.Logging.Spec.FluentdSpec.BufferStorageVolume.ApplyVolumeForPodSpec(r.Logging.QualifiedName(v1beta1.DefaultFluentdBufferStorageVolumeName), containerName, bufferPath, &spec.Template.Spec) + err := r.fluentdSpec.BufferStorageVolume.ApplyVolumeForPodSpec(r.Logging.QualifiedName(v1beta1.DefaultFluentdBufferStorageVolumeName), containerName, bufferPath, &spec.Template.Spec) if err != nil { return nil, reconciler.StatePresent, err } } - for _, n := range r.Logging.Spec.FluentdSpec.ExtraVolumes { + for _, n := range r.fluentdSpec.ExtraVolumes { if n.Volume != nil && n.Volume.PersistentVolumeClaim != nil { if err := n.Volume.ApplyPVCForStatefulSet(n.ContainerName, n.Path, spec, func(name string) metav1.ObjectMeta { return r.FluentdObjectMeta(name, ComponentFluentd) @@ -67,7 +67,7 @@ func (r *Reconciler) statefulset() (runtime.Object, reconciler.DesiredState, err Spec: *spec, } - desired.Annotations = util.MergeLabels(desired.Annotations, r.Logging.Spec.FluentdSpec.StatefulSetAnnotations) + desired.Annotations = util.MergeLabels(desired.Annotations, r.fluentdSpec.StatefulSetAnnotations) return desired, reconciler.StatePresent, nil } @@ -81,25 +81,25 @@ func (r *Reconciler) statefulsetSpec() *appsv1.StatefulSetSpec { if c := r.volumeMountHackContainer(); c != nil { initContainers = append(initContainers, *c) } - if i := generateInitContainer(r.Logging.Spec.FluentdSpec); i != nil { + if i := generateInitContainer(*r.fluentdSpec); i != nil { initContainers = append(initContainers, *i) } containers := []corev1.Container{ - fluentContainer(r.Logging.Spec.FluentdSpec), - *newConfigMapReloader(r.Logging.Spec.FluentdSpec), + fluentContainer(r.fluentdSpec), + *newConfigMapReloader(r.fluentdSpec), } if c := r.bufferMetricsSidecarContainer(); c != nil { containers = append(containers, *c) } - if len(r.Logging.Spec.FluentdSpec.SidecarContainers) != 0 { - containers = append(containers, r.Logging.Spec.FluentdSpec.SidecarContainers...) + if len(r.fluentdSpec.SidecarContainers) != 0 { + containers = append(containers, r.fluentdSpec.SidecarContainers...) } sts := &appsv1.StatefulSetSpec{ - PodManagementPolicy: appsv1.PodManagementPolicyType(r.Logging.Spec.FluentdSpec.Scaling.PodManagementPolicy), + PodManagementPolicy: appsv1.PodManagementPolicyType(r.fluentdSpec.Scaling.PodManagementPolicy), Selector: &metav1.LabelSelector{ - MatchLabels: r.Logging.GetFluentdLabels(ComponentFluentd), + MatchLabels: r.Logging.GetFluentdLabels(ComponentFluentd, *r.fluentdSpec), }, Template: corev1.PodTemplateSpec{ ObjectMeta: r.generatePodMeta(), @@ -107,29 +107,29 @@ func (r *Reconciler) statefulsetSpec() *appsv1.StatefulSetSpec { Volumes: r.generateVolume(), ServiceAccountName: r.getServiceAccount(), InitContainers: initContainers, - ImagePullSecrets: r.Logging.Spec.FluentdSpec.Image.ImagePullSecrets, + ImagePullSecrets: r.fluentdSpec.Image.ImagePullSecrets, Containers: containers, - NodeSelector: r.Logging.Spec.FluentdSpec.NodeSelector, - Tolerations: r.Logging.Spec.FluentdSpec.Tolerations, - Affinity: r.Logging.Spec.FluentdSpec.Affinity, - TopologySpreadConstraints: r.Logging.Spec.FluentdSpec.TopologySpreadConstraints, - PriorityClassName: r.Logging.Spec.FluentdSpec.PodPriorityClassName, - DNSPolicy: r.Logging.Spec.FluentdSpec.DNSPolicy, - DNSConfig: r.Logging.Spec.FluentdSpec.DNSConfig, + NodeSelector: r.fluentdSpec.NodeSelector, + Tolerations: r.fluentdSpec.Tolerations, + Affinity: r.fluentdSpec.Affinity, + TopologySpreadConstraints: r.fluentdSpec.TopologySpreadConstraints, + PriorityClassName: r.fluentdSpec.PodPriorityClassName, + DNSPolicy: r.fluentdSpec.DNSPolicy, + DNSConfig: r.fluentdSpec.DNSConfig, SecurityContext: &corev1.PodSecurityContext{ - RunAsNonRoot: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.RunAsNonRoot, - FSGroup: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.FSGroup, - RunAsUser: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.RunAsUser, - RunAsGroup: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.RunAsGroup, - SeccompProfile: r.Logging.Spec.FluentdSpec.Security.PodSecurityContext.SeccompProfile, + RunAsNonRoot: r.fluentdSpec.Security.PodSecurityContext.RunAsNonRoot, + FSGroup: r.fluentdSpec.Security.PodSecurityContext.FSGroup, + RunAsUser: r.fluentdSpec.Security.PodSecurityContext.RunAsUser, + RunAsGroup: r.fluentdSpec.Security.PodSecurityContext.RunAsGroup, + SeccompProfile: r.fluentdSpec.Security.PodSecurityContext.SeccompProfile, }, }, }, ServiceName: r.Logging.QualifiedName(ServiceName + "-headless"), } - if r.Logging.Spec.FluentdSpec.Scaling.Replicas > 0 { - sts.Replicas = util.IntPointer(cast.ToInt32(r.Logging.Spec.FluentdSpec.Scaling.Replicas)) + if r.fluentdSpec.Scaling.Replicas > 0 { + sts.Replicas = util.IntPointer(cast.ToInt32(r.fluentdSpec.Scaling.Replicas)) } return sts @@ -169,10 +169,10 @@ func fluentContainer(spec *v1beta1.FluentdSpec) corev1.Container { func (r *Reconciler) generatePodMeta() metav1.ObjectMeta { meta := metav1.ObjectMeta{ - Labels: r.Logging.GetFluentdLabels(ComponentFluentd), + Labels: r.Logging.GetFluentdLabels(ComponentFluentd, *r.fluentdSpec), } - if r.Logging.Spec.FluentdSpec.Annotations != nil { - meta.Annotations = r.Logging.Spec.FluentdSpec.Annotations + if r.fluentdSpec.Annotations != nil { + meta.Annotations = r.fluentdSpec.Annotations } return meta } @@ -304,14 +304,14 @@ func (r *Reconciler) generateVolume() (v []corev1.Volume) { }, } - if isFluentdReadOnlyRootFilesystem(r.Logging.Spec.FluentdSpec) { + if isFluentdReadOnlyRootFilesystem(r.fluentdSpec) { v = append(v, corev1.Volume{ Name: "tmp", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}, }) } - if r.Logging.Spec.FluentdSpec.CompressConfigFile { + if r.fluentdSpec.CompressConfigFile { v = append(v, corev1.Volume{ Name: "app-config", VolumeSource: corev1.VolumeSource{ @@ -337,12 +337,12 @@ func (r *Reconciler) generateVolume() (v []corev1.Volume) { }) } - if r.Logging.Spec.FluentdSpec.TLS.Enabled { + if r.fluentdSpec.TLS.Enabled { tlsRelatedVolume := corev1.Volume{ Name: "fluentd-tls", VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: r.Logging.Spec.FluentdSpec.TLS.SecretName, + SecretName: r.fluentdSpec.TLS.SecretName, }, }, } @@ -352,14 +352,14 @@ func (r *Reconciler) generateVolume() (v []corev1.Volume) { } func (r *Reconciler) tmpDirHackContainer() *corev1.Container { - if isFluentdReadOnlyRootFilesystem(r.Logging.Spec.FluentdSpec) { + if isFluentdReadOnlyRootFilesystem(r.fluentdSpec) { return &corev1.Container{ Command: []string{"sh", "-c", "mkdir -p /mnt/tmp/fluentd/; chmod +t /mnt/tmp/fluentd"}, - Image: r.Logging.Spec.FluentdSpec.Image.RepositoryWithTag(), - ImagePullPolicy: corev1.PullPolicy(r.Logging.Spec.FluentdSpec.Image.PullPolicy), + Image: r.fluentdSpec.Image.RepositoryWithTag(), + ImagePullPolicy: corev1.PullPolicy(r.fluentdSpec.Image.PullPolicy), Name: "tmp-dir-hack", - Resources: r.Logging.Spec.FluentdSpec.Resources, - SecurityContext: r.Logging.Spec.FluentdSpec.Security.SecurityContext, + Resources: r.fluentdSpec.Resources, + SecurityContext: r.fluentdSpec.Security.SecurityContext, VolumeMounts: []corev1.VolumeMount{ { Name: "tmp", @@ -371,11 +371,11 @@ func (r *Reconciler) tmpDirHackContainer() *corev1.Container { } func (r *Reconciler) volumeMountHackContainer() *corev1.Container { - if r.Logging.Spec.FluentdSpec.VolumeMountChmod { + if r.fluentdSpec.VolumeMountChmod { return &corev1.Container{ Name: "volume-mount-hack", - Image: r.Logging.Spec.FluentdSpec.VolumeModImage.RepositoryWithTag(), - ImagePullPolicy: corev1.PullPolicy(r.Logging.Spec.FluentdSpec.VolumeModImage.PullPolicy), + Image: r.fluentdSpec.VolumeModImage.RepositoryWithTag(), + ImagePullPolicy: corev1.PullPolicy(r.fluentdSpec.VolumeModImage.PullPolicy), Command: []string{"sh", "-c", "chmod -R 777 " + bufferPath}, VolumeMounts: []corev1.VolumeMount{ { @@ -389,15 +389,15 @@ func (r *Reconciler) volumeMountHackContainer() *corev1.Container { } func (r *Reconciler) bufferMetricsSidecarContainer() *corev1.Container { - if r.Logging.Spec.FluentdSpec.BufferVolumeMetrics != nil { + if r.fluentdSpec.BufferVolumeMetrics != nil { port := int32(defaultBufferVolumeMetricsPort) - if r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.Port != 0 { - port = r.Logging.Spec.FluentdSpec.BufferVolumeMetrics.Port + if r.fluentdSpec.BufferVolumeMetrics.Port != 0 { + port = r.fluentdSpec.BufferVolumeMetrics.Port } portParam := fmt.Sprintf("--web.listen-address=:%d", port) args := []string{portParam} - if len(r.Logging.Spec.FluentdSpec.BufferVolumeArgs) != 0 { - args = append(args, r.Logging.Spec.FluentdSpec.BufferVolumeArgs...) + if len(r.fluentdSpec.BufferVolumeArgs) != 0 { + args = append(args, r.fluentdSpec.BufferVolumeArgs...) } else { args = append(args, "--collector.disable-defaults", "--collector.filesystem", "--collector.textfile", "--collector.textfile.directory=/prometheus/node_exporter/textfile_collector/") } @@ -407,8 +407,8 @@ func (r *Reconciler) bufferMetricsSidecarContainer() *corev1.Container { return &corev1.Container{ Name: "buffer-metrics-sidecar", - Image: r.Logging.Spec.FluentdSpec.BufferVolumeImage.RepositoryWithTag(), - ImagePullPolicy: corev1.PullPolicy(r.Logging.Spec.FluentdSpec.BufferVolumeImage.PullPolicy), + Image: r.fluentdSpec.BufferVolumeImage.RepositoryWithTag(), + ImagePullPolicy: corev1.PullPolicy(r.fluentdSpec.BufferVolumeImage.PullPolicy), Args: []string{ "--exec", nodeExporterCmd, "--exec", bufferSizeCmd, @@ -419,15 +419,15 @@ func (r *Reconciler) bufferMetricsSidecarContainer() *corev1.Container { Value: bufferPath, }, }, - Ports: generatePortsBufferVolumeMetrics(r.Logging.Spec.FluentdSpec), + Ports: generatePortsBufferVolumeMetrics(r.fluentdSpec), VolumeMounts: []corev1.VolumeMount{ { Name: r.bufferVolumeName(), MountPath: bufferPath, }, }, - Resources: r.Logging.Spec.FluentdSpec.BufferVolumeResources, - SecurityContext: r.Logging.Spec.FluentdSpec.Security.SecurityContext, + Resources: r.fluentdSpec.BufferVolumeResources, + SecurityContext: r.fluentdSpec.Security.SecurityContext, } } return nil @@ -435,8 +435,8 @@ func (r *Reconciler) bufferMetricsSidecarContainer() *corev1.Container { func (r *Reconciler) bufferVolumeName() string { volumeName := r.Logging.QualifiedName(v1beta1.DefaultFluentdBufferStorageVolumeName) - if r.Logging.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim != nil { - volumeName = r.Logging.QualifiedName(r.Logging.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeSource.ClaimName) + if r.fluentdSpec.BufferStorageVolume.PersistentVolumeClaim != nil { + volumeName = r.Logging.QualifiedName(r.fluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeSource.ClaimName) } return volumeName } @@ -479,7 +479,7 @@ func generateReadinessCheck(spec *v1beta1.FluentdSpec) *corev1.Probe { return nil } -func generateInitContainer(spec *v1beta1.FluentdSpec) *corev1.Container { +func generateInitContainer(spec v1beta1.FluentdSpec) *corev1.Container { if spec.CompressConfigFile { return &corev1.Container{ Name: "init-config-reloader", diff --git a/pkg/resources/model/reconciler.go b/pkg/resources/model/reconciler.go index f9563d080..236d14f75 100644 --- a/pkg/resources/model/reconciler.go +++ b/pkg/resources/model/reconciler.go @@ -41,6 +41,7 @@ func NewValidationReconciler( logger logr.Logger, ) func(ctx context.Context) (*reconcile.Result, error) { return func(ctx context.Context) (*reconcile.Result, error) { + // Make sure that you call registerForPatching() before modifying the object var patchRequests []patchRequest registerForPatching := func(obj client.Object) { patchRequests = append(patchRequests, patchRequest{ @@ -207,6 +208,38 @@ func NewValidationReconciler( resources.Logging.Status.Problems = nil resources.Logging.Status.WatchNamespaces = nil + if len(resources.Fluentd.ExcessFluentds) != 0 { + logger.Info("Excess Fluentd CRDs found") + resources.Logging.Status.Problems = append(resources.Logging.Status.Problems, "multiple fluentd configurations found, couldn't associate it with logging") + for i := range resources.Fluentd.ExcessFluentds { + excessFluentd := &resources.Fluentd.ExcessFluentds[i] + registerForPatching(excessFluentd) + excessFluentd.Status.Problems = nil + excessFluentd.Status.Active = utils.BoolPointer(false) + excessFluentd.Status.Logging = "" + + if len(resources.Logging.Status.FluentdConfigName) == 0 { + excessFluentd.Status.Problems = append(excessFluentd.Status.Problems, "multiple fluentd configurations found, couldn't associate it with logging") + } else if resources.Logging.Status.FluentdConfigName != excessFluentd.Name { + excessFluentd.Status.Problems = append(excessFluentd.Status.Problems, "logging already has a detached fluentd configuration, remove excess configuration objects") + } + excessFluentd.Status.ProblemsCount = len(excessFluentd.Status.Problems) + } + } + if resources.Fluentd.Configuration != nil { + registerForPatching(resources.Fluentd.Configuration) + + if resources.Logging.Spec.FluentdSpec != nil { + resources.Logging.Status.Problems = append(resources.Logging.Status.Problems, fmt.Sprintf("Fluentd configuration reference set (name=%s), but inline fluentd configuration is set as well, clearing inline", resources.Fluentd.Configuration.Name)) + resources.Logging.Spec.FluentdSpec = nil + } + logger.Info("found detached fluentd aggregator, making association", "name", resources.Fluentd.Configuration.Name) + resources.Logging.Status.FluentdConfigName = resources.Fluentd.Configuration.Name + + resources.Fluentd.Configuration.Status.Active = utils.BoolPointer(true) + resources.Fluentd.Configuration.Status.Logging = resources.Logging.Name + } + if !resources.Logging.WatchAllNamespaces() { resources.Logging.Status.WatchNamespaces = resources.WatchNamespaces } diff --git a/pkg/resources/model/repository.go b/pkg/resources/model/repository.go index 0af7b8d4c..79529932a 100644 --- a/pkg/resources/model/repository.go +++ b/pkg/resources/model/repository.go @@ -57,6 +57,9 @@ func (r LoggingResourceRepository) LoggingResourcesFor(ctx context.Context, logg res.Fluentd.ClusterOutputs, err = r.ClusterOutputsFor(ctx, logging) errs = errors.Append(errs, err) + res.Fluentd.Configuration, res.Fluentd.ExcessFluentds, err = r.FluentdConfigFor(ctx, logging) + errs = errors.Append(errs, err) + res.SyslogNG.ClusterFlows, err = r.SyslogNGClusterFlowsFor(ctx, logging) errs = errors.Append(errs, err) @@ -334,6 +337,47 @@ func (r LoggingResourceRepository) FluentbitsFor(ctx context.Context, logging v1 }) return res, nil } +func (r LoggingResourceRepository) handleMultipleDetachedFluentdObjects(list []v1beta1.FluentdConfig, logging v1beta1.Logging) []v1beta1.FluentdConfig { + + r.Logger.Info("multiple detached Fluentd CRDs found") + + var excessFluentds []v1beta1.FluentdConfig + for _, i := range list { + if len(logging.Status.FluentdConfigName) != 0 { + if i.Name != logging.Status.FluentdConfigName { + excessFluentds = append(excessFluentds, i) + } + } else { + // No association, mark everything as excess + excessFluentds = append(excessFluentds, i) + } + } + + return excessFluentds +} + +func (r LoggingResourceRepository) FluentdConfigFor(ctx context.Context, logging v1beta1.Logging) (*v1beta1.FluentdConfig, []v1beta1.FluentdConfig, error) { + var list v1beta1.FluentdConfigList + if err := r.Client.List(ctx, &list); err != nil { + return nil, []v1beta1.FluentdConfig{}, err + } + + var res []v1beta1.FluentdConfig + res = append(res, list.Items...) + + switch len(res) { + case 0: + return nil, []v1beta1.FluentdConfig{}, nil + case 1: + // Implicitly associate fluentd configuration object with logging + detachedFluentd := res[0] + err := detachedFluentd.Spec.SetDefaults() + return &detachedFluentd, []v1beta1.FluentdConfig{}, err + default: + excessFluentds := r.handleMultipleDetachedFluentdObjects(res, logging) + return nil, excessFluentds, nil + } +} func (r LoggingResourceRepository) LoggingRoutesFor(ctx context.Context, logging v1beta1.Logging) ([]v1beta1.LoggingRoute, error) { var list v1beta1.LoggingRouteList diff --git a/pkg/resources/model/resources.go b/pkg/resources/model/resources.go index 3be9ae251..9a9386b90 100644 --- a/pkg/resources/model/resources.go +++ b/pkg/resources/model/resources.go @@ -29,11 +29,32 @@ type LoggingResources struct { WatchNamespaces []string } +func (l LoggingResources) GetFluentd() *v1beta1.FluentdConfig { + if l.Fluentd.Configuration != nil { + return l.Fluentd.Configuration + } + return nil +} + +func (l LoggingResources) GetFluentdSpec() *v1beta1.FluentdSpec { + + if detachedFluentd := l.GetFluentd(); detachedFluentd != nil { + return &detachedFluentd.Spec + } + if l.Logging.Spec.FluentdSpec != nil { + return l.Logging.Spec.FluentdSpec + } + + return nil +} + type FluentdLoggingResources struct { ClusterFlows []v1beta1.ClusterFlow ClusterOutputs ClusterOutputs Flows []v1beta1.Flow Outputs Outputs + Configuration *v1beta1.FluentdConfig + ExcessFluentds []v1beta1.FluentdConfig } type SyslogNGLoggingResources struct { diff --git a/pkg/resources/model/system.go b/pkg/resources/model/system.go index 5a295af46..5ac622879 100644 --- a/pkg/resources/model/system.go +++ b/pkg/resources/model/system.go @@ -32,15 +32,16 @@ import ( func CreateSystem(resources LoggingResources, secrets SecretLoaderFactory, logger logr.Logger) (*types.System, error) { logging := resources.Logging + fluentdSpec := resources.GetFluentdSpec() var forwardInput *input.ForwardInputConfig - if logging.Spec.FluentdSpec != nil && logging.Spec.FluentdSpec.ForwardInputConfig != nil { - forwardInput = logging.Spec.FluentdSpec.ForwardInputConfig + if fluentdSpec != nil && fluentdSpec.ForwardInputConfig != nil { + forwardInput = fluentdSpec.ForwardInputConfig } else { forwardInput = input.NewForwardInputConfig() } - if logging.Spec.FluentdSpec != nil && logging.Spec.FluentdSpec.TLS.Enabled { + if fluentdSpec != nil && fluentdSpec.TLS.Enabled { forwardInput.Transport = &common.Transport{ Version: "TLSv1_2", CaPath: "/fluentd/tls/ca.crt", @@ -50,7 +51,7 @@ func CreateSystem(resources LoggingResources, secrets SecretLoaderFactory, logge } forwardInput.Security = &common.Security{ SelfHostname: "fluentd", - SharedKey: logging.Spec.FluentdSpec.TLS.SharedKey, + SharedKey: fluentdSpec.TLS.SharedKey, } } @@ -60,7 +61,7 @@ func CreateSystem(resources LoggingResources, secrets SecretLoaderFactory, logge } router := types.NewRouter("main", types.Params{ - "metrics": strconv.FormatBool(logging.Spec.FluentdSpec.Metrics != nil), + "metrics": strconv.FormatBool(fluentdSpec.Metrics != nil), }) var globalFilters []types.Filter @@ -151,7 +152,7 @@ func CreateSystem(resources LoggingResources, secrets SecretLoaderFactory, logge } // TODO: wow such hack - if logging.Spec.FluentdSpec.Workers > 1 { + if fluentdSpec.Workers > 1 { for _, flow := range system.Flows { for _, output := range flow.Outputs { unsetBufferPath(output) diff --git a/pkg/resources/nodeagent/configsecret.go b/pkg/resources/nodeagent/configsecret.go index 17fbb95d8..0ce550012 100644 --- a/pkg/resources/nodeagent/configsecret.go +++ b/pkg/resources/nodeagent/configsecret.go @@ -326,6 +326,6 @@ func (n *nodeAgentInstance) generateUpstreamNode(index int32) upstreamNode { n.FluentdQualifiedName(fluentd.ServiceName+"-headless"), n.logging.Spec.ControlNamespace, n.logging.ClusterDomainAsSuffix()), - Port: n.logging.Spec.FluentdSpec.Port, + Port: n.fluentdSpec.Port, } } diff --git a/pkg/resources/nodeagent/nodeagent.go b/pkg/resources/nodeagent/nodeagent.go index c2a8623f6..cc7d4ab5e 100644 --- a/pkg/resources/nodeagent/nodeagent.go +++ b/pkg/resources/nodeagent/nodeagent.go @@ -269,7 +269,8 @@ func (n *nodeAgentInstance) getServiceAccount() string { // // Reconciler holds info what resource to reconcile type Reconciler struct { - Logging *v1beta1.Logging + Logging *v1beta1.Logging + fluentdSpec *v1beta1.FluentdSpec *reconciler.GenericResourceReconciler configs map[string][]byte agents map[string]v1beta1.NodeAgentConfig @@ -277,12 +278,13 @@ type Reconciler struct { } // New creates a new NodeAgent reconciler -func New(client client.Client, logger logr.Logger, logging *v1beta1.Logging, agents map[string]v1beta1.NodeAgentConfig, opts reconciler.ReconcilerOpts, fluentdDataProvider loggingdataprovider.LoggingDataProvider) *Reconciler { +func New(client client.Client, logger logr.Logger, logging *v1beta1.Logging, fluentdSpec *v1beta1.FluentdSpec, agents map[string]v1beta1.NodeAgentConfig, opts reconciler.ReconcilerOpts, fluentdDataProvider loggingdataprovider.LoggingDataProvider) *Reconciler { return &Reconciler{ Logging: logging, GenericResourceReconciler: reconciler.NewGenericReconciler(client, logger, opts), agents: agents, fluentdDataProvider: fluentdDataProvider, + fluentdSpec: fluentdSpec, } } @@ -291,6 +293,7 @@ type nodeAgentInstance struct { nodeAgent *v1beta1.NodeAgentConfig reconciler *reconciler.GenericResourceReconciler logging *v1beta1.Logging + fluentdSpec *v1beta1.FluentdSpec configs map[string][]byte loggingDataProvider loggingdataprovider.LoggingDataProvider } @@ -340,6 +343,7 @@ func (r *Reconciler) processAgent(ctx context.Context, name string, userDefinedA reconciler: r.GenericResourceReconciler, logging: r.Logging, loggingDataProvider: r.fluentdDataProvider, + fluentdSpec: r.fluentdSpec, } return instance.Reconcile(ctx) diff --git a/pkg/sdk/logging/api/v1beta1/conversion.go b/pkg/sdk/logging/api/v1beta1/conversion.go index ca2144fe7..1265ea2b0 100644 --- a/pkg/sdk/logging/api/v1beta1/conversion.go +++ b/pkg/sdk/logging/api/v1beta1/conversion.go @@ -48,11 +48,12 @@ func APITypes() []runtime.Object { func (l *Logging) Default() { Log.Info("Defaulter called for", "logging", l) if l.Spec.FluentdSpec != nil { - if l.Spec.FluentdSpec.Scaling == nil { - l.Spec.FluentdSpec.Scaling = new(FluentdScaling) + fluentdSpec := l.Spec.FluentdSpec + if fluentdSpec.Scaling == nil { + fluentdSpec.Scaling = new(FluentdScaling) } - if l.Spec.FluentdSpec.Scaling.PodManagementPolicy == "" { - l.Spec.FluentdSpec.Scaling.PodManagementPolicy = string(appsv1.ParallelPodManagement) + if fluentdSpec.Scaling.PodManagementPolicy == "" { + fluentdSpec.Scaling.PodManagementPolicy = string(appsv1.ParallelPodManagement) } } else { Log.Info("l.Spec.FluentdSpec is missing, skipping Defaulter") diff --git a/pkg/sdk/logging/api/v1beta1/fluentd_types.go b/pkg/sdk/logging/api/v1beta1/fluentd_types.go index d0accdce6..a4e225445 100644 --- a/pkg/sdk/logging/api/v1beta1/fluentd_types.go +++ b/pkg/sdk/logging/api/v1beta1/fluentd_types.go @@ -15,9 +15,16 @@ package v1beta1 import ( + "errors" + "fmt" + "github.com/cisco-open/operator-tools/pkg/typeoverride" + util "github.com/cisco-open/operator-tools/pkg/utils" "github.com/cisco-open/operator-tools/pkg/volume" + "github.com/spf13/cast" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/kube-logging/logging-operator/pkg/sdk/logging/model/input" ) @@ -101,6 +108,52 @@ type FluentdSpec struct { SidecarContainers []corev1.Container `json:"sidecarContainers,omitempty"` } +// +name:"FluentdConfig" +// +weight:"200" +type _hugoFluent interface{} //nolint:deadcode,unused + +// +name:"Fluent" +// +version:"v1beta1" +// +description:"FluentdConfig is a reference to the desired Fluentd state" +type _metaFluentdConfig interface{} //nolint:deadcode,unused + +// +kubebuilder:object:root=true +// +kubebuilder:resource:categories=logging-all +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Active",type="boolean",JSONPath=".status.active",description="Is the fluentd configuration active?" +// +kubebuilder:printcolumn:name="Problems",type="integer",JSONPath=".status.problemsCount",description="Number of problems" +// +kubebuilder:storageversion + +// FluentdConfig +type FluentdConfig struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec FluentdSpec `json:"spec,omitempty"` + Status FluentdConfigStatus `json:"status,omitempty"` +} + +// FluentdConfigStatus +type FluentdConfigStatus struct { + Logging string `json:"logging,omitempty"` + Active *bool `json:"active,omitempty"` + Problems []string `json:"problems,omitempty"` + ProblemsCount int `json:"problemsCount,omitempty"` +} + +// +kubebuilder:object:root=true + +// FluentdConfigList +type FluentdConfigList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []FluentdConfig `json:"items"` +} + +func init() { + SchemeBuilder.Register(&FluentdConfig{}, &FluentdConfigList{}) +} + // +kubebuilder:object:generate=true type FluentOutLogrotate struct { @@ -110,6 +163,265 @@ type FluentOutLogrotate struct { Size string `json:"size,omitempty"` } +// GetFluentdMetricsPath returns the right Fluentd metrics endpoint +// depending on the number of workers and the user configuration +func (f *FluentdSpec) GetFluentdMetricsPath() string { + if f.Metrics.Path == "" { + if f.Workers > 1 { + return "/aggregated_metrics" + } + return "/metrics" + } + return f.Metrics.Path +} + +func (f *FluentdSpec) SetDefaults() error { + if f != nil { // nolint:nestif + if f.FluentdPvcSpec != nil { + return errors.New("`fluentdPvcSpec` field is deprecated, use: `bufferStorageVolume`") + } + if f.Image.Repository == "" { + f.Image.Repository = DefaultFluentdImageRepository + } + if f.Image.Tag == "" { + f.Image.Tag = DefaultFluentdImageTag + } + if f.Image.PullPolicy == "" { + f.Image.PullPolicy = "IfNotPresent" + } + if f.Annotations == nil { + f.Annotations = make(map[string]string) + } + if f.Security == nil { + f.Security = &Security{} + } + if f.Security.RoleBasedAccessControlCreate == nil { + f.Security.RoleBasedAccessControlCreate = util.BoolPointer(true) + } + if f.Security.SecurityContext == nil { + f.Security.SecurityContext = &corev1.SecurityContext{} + } + if f.Security.PodSecurityContext == nil { + f.Security.PodSecurityContext = &corev1.PodSecurityContext{} + } + if f.Security.PodSecurityContext.FSGroup == nil { + f.Security.PodSecurityContext.FSGroup = util.IntPointer64(101) + } + if f.Workers <= 0 { + f.Workers = 1 + } + if f.Metrics != nil { + if f.Metrics.Port == 0 { + f.Metrics.Port = 24231 + } + if f.Metrics.Timeout == "" { + f.Metrics.Timeout = "5s" + } + if f.Metrics.Interval == "" { + f.Metrics.Interval = "15s" + } + if f.Metrics.PrometheusAnnotations { + f.Annotations["prometheus.io/scrape"] = "true" + f.Annotations["prometheus.io/path"] = f.GetFluentdMetricsPath() + f.Annotations["prometheus.io/port"] = fmt.Sprintf("%d", f.Metrics.Port) + } + } + if f.LogLevel == "" { + f.LogLevel = "info" + } + if !f.DisablePvc { + if f.BufferStorageVolume.PersistentVolumeClaim == nil { + f.BufferStorageVolume.PersistentVolumeClaim = &volume.PersistentVolumeClaim{ + PersistentVolumeClaimSpec: corev1.PersistentVolumeClaimSpec{}, + } + } + if f.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.AccessModes == nil { + f.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.AccessModes = []corev1.PersistentVolumeAccessMode{ + corev1.ReadWriteOnce, + } + } + if f.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.Resources.Requests == nil { + f.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.Resources.Requests = map[corev1.ResourceName]resource.Quantity{ + "storage": resource.MustParse("20Gi"), + } + } + if f.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.VolumeMode == nil { + f.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.VolumeMode = persistentVolumeModePointer(corev1.PersistentVolumeFilesystem) + } + if f.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeSource.ClaimName == "" { + f.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeSource.ClaimName = DefaultFluentdBufferStorageVolumeName + } + } + if f.VolumeModImage.Repository == "" { + f.VolumeModImage.Repository = DefaultFluentdVolumeModeImageRepository + } + if f.VolumeModImage.Tag == "" { + f.VolumeModImage.Tag = DefaultFluentdVolumeModeImageTag + } + if f.VolumeModImage.PullPolicy == "" { + f.VolumeModImage.PullPolicy = "IfNotPresent" + } + if f.ConfigReloaderImage.Repository == "" { + f.ConfigReloaderImage.Repository = DefaultFluentdConfigReloaderImageRepository + } + if f.ConfigReloaderImage.Tag == "" { + f.ConfigReloaderImage.Tag = DefaultFluentdConfigReloaderImageTag + } + if f.ConfigReloaderImage.PullPolicy == "" { + f.ConfigReloaderImage.PullPolicy = "IfNotPresent" + } + if f.BufferVolumeImage.Repository == "" { + f.BufferVolumeImage.Repository = DefaultFluentdBufferVolumeImageRepository + } + if f.BufferVolumeImage.Tag == "" { + f.BufferVolumeImage.Tag = DefaultFluentdBufferVolumeImageTag + } + if f.BufferVolumeImage.PullPolicy == "" { + f.BufferVolumeImage.PullPolicy = "IfNotPresent" + } + if f.BufferVolumeResources.Limits == nil { + f.BufferVolumeResources.Limits = corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("10M"), + corev1.ResourceCPU: resource.MustParse("50m"), + } + } + if f.BufferVolumeResources.Requests == nil { + f.BufferVolumeResources.Requests = corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("10M"), + corev1.ResourceCPU: resource.MustParse("1m"), + } + } + if f.Resources.Limits == nil { + f.Resources.Limits = corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("400M"), + corev1.ResourceCPU: resource.MustParse("1000m"), + } + } + if f.Resources.Requests == nil { + f.Resources.Requests = corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("100M"), + corev1.ResourceCPU: resource.MustParse("500m"), + } + } + if f.Port == 0 { + f.Port = 24240 + } + if f.Scaling == nil { + f.Scaling = new(FluentdScaling) + } + if f.Scaling.PodManagementPolicy == "" { + f.Scaling.PodManagementPolicy = "OrderedReady" + } + if f.Scaling.Drain.Image.Repository == "" { + f.Scaling.Drain.Image.Repository = DefaultFluentdDrainWatchImageRepository + } + if f.Scaling.Drain.Image.Tag == "" { + f.Scaling.Drain.Image.Tag = DefaultFluentdDrainWatchImageTag + } + if f.Scaling.Drain.Image.PullPolicy == "" { + f.Scaling.Drain.Image.PullPolicy = "IfNotPresent" + } + if f.Scaling.Drain.PauseImage.Repository == "" { + f.Scaling.Drain.PauseImage.Repository = DefaultFluentdDrainPauseImageRepository + } + if f.Scaling.Drain.PauseImage.Tag == "" { + f.Scaling.Drain.PauseImage.Tag = DefaultFluentdDrainPauseImageTag + } + if f.Scaling.Drain.PauseImage.PullPolicy == "" { + f.Scaling.Drain.PauseImage.PullPolicy = "IfNotPresent" + } + if f.Scaling.Drain.Resources == nil { + f.Scaling.Drain.Resources = &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("50M"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("20m"), + }, + } + } + if f.Scaling.Drain.SecurityContext == nil { + f.Scaling.Drain.SecurityContext = f.Security.SecurityContext.DeepCopy() + } + if f.FluentLogDestination == "" { + f.FluentLogDestination = "null" + } + if f.FluentOutLogrotate == nil { + f.FluentOutLogrotate = &FluentOutLogrotate{ + Enabled: false, + } + } + if _, ok := f.Annotations["fluentbit.io/exclude"]; !ok { + f.Annotations["fluentbit.io/exclude"] = "true" + } + if f.FluentOutLogrotate.Path == "" { + f.FluentOutLogrotate.Path = "/fluentd/log/out" + } + if f.FluentOutLogrotate.Age == "" { + f.FluentOutLogrotate.Age = "10" + } + if f.FluentOutLogrotate.Size == "" { + f.FluentOutLogrotate.Size = cast.ToString(1024 * 1024 * 10) + } + if f.LivenessProbe == nil { + if f.LivenessDefaultCheck { + f.LivenessProbe = &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + Exec: &corev1.ExecAction{Command: []string{"/bin/healthy.sh"}}, + }, + InitialDelaySeconds: 600, + TimeoutSeconds: 0, + PeriodSeconds: 60, + SuccessThreshold: 0, + FailureThreshold: 0, + } + } + } + if f.ReadinessDefaultCheck.BufferFreeSpace { + if f.ReadinessDefaultCheck.BufferFreeSpaceThreshold == 0 { + f.ReadinessDefaultCheck.BufferFreeSpaceThreshold = 90 + } + } + + if f.ReadinessDefaultCheck.BufferFileNumber { + if f.ReadinessDefaultCheck.BufferFileNumberMax == 0 { + f.ReadinessDefaultCheck.BufferFileNumberMax = 5000 + } + } + if f.ReadinessDefaultCheck.InitialDelaySeconds == 0 { + f.ReadinessDefaultCheck.InitialDelaySeconds = 5 + } + if f.ReadinessDefaultCheck.TimeoutSeconds == 0 { + f.ReadinessDefaultCheck.TimeoutSeconds = 3 + } + if f.ReadinessDefaultCheck.PeriodSeconds == 0 { + f.ReadinessDefaultCheck.PeriodSeconds = 30 + } + if f.ReadinessDefaultCheck.SuccessThreshold == 0 { + f.ReadinessDefaultCheck.SuccessThreshold = 3 + } + if f.ReadinessDefaultCheck.FailureThreshold == 0 { + f.ReadinessDefaultCheck.FailureThreshold = 1 + } + for i := range f.ExtraVolumes { + e := &f.ExtraVolumes[i] + if e.ContainerName == "" { + e.ContainerName = "fluentd" + } + if e.VolumeName == "" { + e.VolumeName = fmt.Sprintf("extravolume-%d", i) + } + if e.Path == "" { + e.Path = "/tmp" + } + if e.Volume == nil { + e.Volume = &volume.KubernetesVolume{} + } + } + } + return nil +} + // +kubebuilder:object:generate=true // ExtraVolume defines the fluentd extra volumes diff --git a/pkg/sdk/logging/api/v1beta1/logging_types.go b/pkg/sdk/logging/api/v1beta1/logging_types.go index abf929771..5353b3249 100644 --- a/pkg/sdk/logging/api/v1beta1/logging_types.go +++ b/pkg/sdk/logging/api/v1beta1/logging_types.go @@ -19,8 +19,6 @@ import ( "fmt" util "github.com/cisco-open/operator-tools/pkg/utils" - "github.com/cisco-open/operator-tools/pkg/volume" - "github.com/spf13/cast" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -111,6 +109,8 @@ type ConfigCheck struct { type LoggingStatus struct { // Result of the config check. Under normal conditions there is a single item in the map with a bool value. ConfigCheckResults map[string]bool `json:"configCheckResults,omitempty"` + // Name of the matched detached fluentd configuration object + FluentdConfigName string `json:"fluentdConfigName,omitempty"` // Problems with the logging resource Problems []string `json:"problems,omitempty"` @@ -189,253 +189,14 @@ func (l *Logging) SetDefaults() error { if !l.Spec.FlowConfigCheckDisabled && l.Status.ConfigCheckResults == nil { l.Status.ConfigCheckResults = make(map[string]bool) } - if l.Spec.FluentdSpec != nil { // nolint:nestif - if l.Spec.FluentdSpec.FluentdPvcSpec != nil { - return errors.New("`fluentdPvcSpec` field is deprecated, use: `bufferStorageVolume`") - } - if l.Spec.FluentdSpec.Image.Repository == "" { - l.Spec.FluentdSpec.Image.Repository = DefaultFluentdImageRepository - } - if l.Spec.FluentdSpec.Image.Tag == "" { - l.Spec.FluentdSpec.Image.Tag = DefaultFluentdImageTag - } - if l.Spec.FluentdSpec.Image.PullPolicy == "" { - l.Spec.FluentdSpec.Image.PullPolicy = "IfNotPresent" - } - if l.Spec.FluentdSpec.Annotations == nil { - l.Spec.FluentdSpec.Annotations = make(map[string]string) - } - if l.Spec.FluentdSpec.Security == nil { - l.Spec.FluentdSpec.Security = &Security{} - } - if l.Spec.FluentdSpec.Security.RoleBasedAccessControlCreate == nil { - l.Spec.FluentdSpec.Security.RoleBasedAccessControlCreate = util.BoolPointer(true) - } - if l.Spec.FluentdSpec.Security.SecurityContext == nil { - l.Spec.FluentdSpec.Security.SecurityContext = &v1.SecurityContext{} - } - if l.Spec.FluentdSpec.Security.PodSecurityContext == nil { - l.Spec.FluentdSpec.Security.PodSecurityContext = &v1.PodSecurityContext{} - } - if l.Spec.FluentdSpec.Security.PodSecurityContext.FSGroup == nil { - l.Spec.FluentdSpec.Security.PodSecurityContext.FSGroup = util.IntPointer64(101) - } - if l.Spec.FluentdSpec.Workers <= 0 { - l.Spec.FluentdSpec.Workers = 1 - } - if l.Spec.FluentdSpec.Metrics != nil { - if l.Spec.FluentdSpec.Metrics.Port == 0 { - l.Spec.FluentdSpec.Metrics.Port = 24231 - } - if l.Spec.FluentdSpec.Metrics.Timeout == "" { - l.Spec.FluentdSpec.Metrics.Timeout = "5s" - } - if l.Spec.FluentdSpec.Metrics.Interval == "" { - l.Spec.FluentdSpec.Metrics.Interval = "15s" - } - if l.Spec.FluentdSpec.Metrics.PrometheusAnnotations { - l.Spec.FluentdSpec.Annotations["prometheus.io/scrape"] = "true" - l.Spec.FluentdSpec.Annotations["prometheus.io/path"] = l.GetFluentdMetricsPath() - l.Spec.FluentdSpec.Annotations["prometheus.io/port"] = fmt.Sprintf("%d", l.Spec.FluentdSpec.Metrics.Port) - } - } - if l.Spec.FluentdSpec.LogLevel == "" { - l.Spec.FluentdSpec.LogLevel = "info" - } - if !l.Spec.FluentdSpec.DisablePvc { - if l.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim == nil { - l.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim = &volume.PersistentVolumeClaim{ - PersistentVolumeClaimSpec: v1.PersistentVolumeClaimSpec{}, - } - } - if l.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.AccessModes == nil { - l.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.AccessModes = []v1.PersistentVolumeAccessMode{ - v1.ReadWriteOnce, - } - } - if l.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.Resources.Requests == nil { - l.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.Resources.Requests = map[v1.ResourceName]resource.Quantity{ - "storage": resource.MustParse("20Gi"), - } - } - if l.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.VolumeMode == nil { - l.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeClaimSpec.VolumeMode = persistentVolumeModePointer(v1.PersistentVolumeFilesystem) - } - if l.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeSource.ClaimName == "" { - l.Spec.FluentdSpec.BufferStorageVolume.PersistentVolumeClaim.PersistentVolumeSource.ClaimName = DefaultFluentdBufferStorageVolumeName - } - } - if l.Spec.FluentdSpec.VolumeModImage.Repository == "" { - l.Spec.FluentdSpec.VolumeModImage.Repository = DefaultFluentdVolumeModeImageRepository - } - if l.Spec.FluentdSpec.VolumeModImage.Tag == "" { - l.Spec.FluentdSpec.VolumeModImage.Tag = DefaultFluentdVolumeModeImageTag - } - if l.Spec.FluentdSpec.VolumeModImage.PullPolicy == "" { - l.Spec.FluentdSpec.VolumeModImage.PullPolicy = "IfNotPresent" - } - if l.Spec.FluentdSpec.ConfigReloaderImage.Repository == "" { - l.Spec.FluentdSpec.ConfigReloaderImage.Repository = DefaultFluentdConfigReloaderImageRepository - } - if l.Spec.FluentdSpec.ConfigReloaderImage.Tag == "" { - l.Spec.FluentdSpec.ConfigReloaderImage.Tag = DefaultFluentdConfigReloaderImageTag - } - if l.Spec.FluentdSpec.ConfigReloaderImage.PullPolicy == "" { - l.Spec.FluentdSpec.ConfigReloaderImage.PullPolicy = "IfNotPresent" - } - if l.Spec.FluentdSpec.BufferVolumeImage.Repository == "" { - l.Spec.FluentdSpec.BufferVolumeImage.Repository = DefaultFluentdBufferVolumeImageRepository - } - if l.Spec.FluentdSpec.BufferVolumeImage.Tag == "" { - l.Spec.FluentdSpec.BufferVolumeImage.Tag = DefaultFluentdBufferVolumeImageTag - } - if l.Spec.FluentdSpec.BufferVolumeImage.PullPolicy == "" { - l.Spec.FluentdSpec.BufferVolumeImage.PullPolicy = "IfNotPresent" - } - if l.Spec.FluentdSpec.BufferVolumeResources.Limits == nil { - l.Spec.FluentdSpec.BufferVolumeResources.Limits = v1.ResourceList{ - v1.ResourceMemory: resource.MustParse("10M"), - v1.ResourceCPU: resource.MustParse("50m"), - } - } - if l.Spec.FluentdSpec.BufferVolumeResources.Requests == nil { - l.Spec.FluentdSpec.BufferVolumeResources.Requests = v1.ResourceList{ - v1.ResourceMemory: resource.MustParse("10M"), - v1.ResourceCPU: resource.MustParse("1m"), - } - } - if l.Spec.FluentdSpec.Resources.Limits == nil { - l.Spec.FluentdSpec.Resources.Limits = v1.ResourceList{ - v1.ResourceMemory: resource.MustParse("400M"), - v1.ResourceCPU: resource.MustParse("1000m"), - } - } - if l.Spec.FluentdSpec.Resources.Requests == nil { - l.Spec.FluentdSpec.Resources.Requests = v1.ResourceList{ - v1.ResourceMemory: resource.MustParse("100M"), - v1.ResourceCPU: resource.MustParse("500m"), - } - } - if l.Spec.FluentdSpec.Port == 0 { - l.Spec.FluentdSpec.Port = 24240 - } - if l.Spec.FluentdSpec.Scaling == nil { - l.Spec.FluentdSpec.Scaling = new(FluentdScaling) - } - if l.Spec.FluentdSpec.Scaling.PodManagementPolicy == "" { - l.Spec.FluentdSpec.Scaling.PodManagementPolicy = "OrderedReady" - } - if l.Spec.FluentdSpec.Scaling.Drain.Image.Repository == "" { - l.Spec.FluentdSpec.Scaling.Drain.Image.Repository = DefaultFluentdDrainWatchImageRepository - } - if l.Spec.FluentdSpec.Scaling.Drain.Image.Tag == "" { - l.Spec.FluentdSpec.Scaling.Drain.Image.Tag = DefaultFluentdDrainWatchImageTag - } - if l.Spec.FluentdSpec.Scaling.Drain.Image.PullPolicy == "" { - l.Spec.FluentdSpec.Scaling.Drain.Image.PullPolicy = "IfNotPresent" - } - if l.Spec.FluentdSpec.Scaling.Drain.PauseImage.Repository == "" { - l.Spec.FluentdSpec.Scaling.Drain.PauseImage.Repository = DefaultFluentdDrainPauseImageRepository - } - if l.Spec.FluentdSpec.Scaling.Drain.PauseImage.Tag == "" { - l.Spec.FluentdSpec.Scaling.Drain.PauseImage.Tag = DefaultFluentdDrainPauseImageTag - } - if l.Spec.FluentdSpec.Scaling.Drain.PauseImage.PullPolicy == "" { - l.Spec.FluentdSpec.Scaling.Drain.PauseImage.PullPolicy = "IfNotPresent" - } - if l.Spec.FluentdSpec.Scaling.Drain.Resources == nil { - l.Spec.FluentdSpec.Scaling.Drain.Resources = &v1.ResourceRequirements{ - Limits: v1.ResourceList{ - v1.ResourceMemory: resource.MustParse("50M"), - }, - Requests: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("20m"), - }, - } - } - if l.Spec.FluentdSpec.Scaling.Drain.SecurityContext == nil { - l.Spec.FluentdSpec.Scaling.Drain.SecurityContext = l.Spec.FluentdSpec.Security.SecurityContext.DeepCopy() - } - if l.Spec.FluentdSpec.FluentLogDestination == "" { - l.Spec.FluentdSpec.FluentLogDestination = "null" - } - if l.Spec.FluentdSpec.FluentOutLogrotate == nil { - l.Spec.FluentdSpec.FluentOutLogrotate = &FluentOutLogrotate{ - Enabled: false, - } - } - if _, ok := l.Spec.FluentdSpec.Annotations["fluentbit.io/exclude"]; !ok { - l.Spec.FluentdSpec.Annotations["fluentbit.io/exclude"] = "true" - } - if l.Spec.FluentdSpec.FluentOutLogrotate.Path == "" { - l.Spec.FluentdSpec.FluentOutLogrotate.Path = "/fluentd/log/out" - } - if l.Spec.FluentdSpec.FluentOutLogrotate.Age == "" { - l.Spec.FluentdSpec.FluentOutLogrotate.Age = "10" - } - if l.Spec.FluentdSpec.FluentOutLogrotate.Size == "" { - l.Spec.FluentdSpec.FluentOutLogrotate.Size = cast.ToString(1024 * 1024 * 10) - } - if l.Spec.FluentdSpec.LivenessProbe == nil { - if l.Spec.FluentdSpec.LivenessDefaultCheck { - l.Spec.FluentdSpec.LivenessProbe = &v1.Probe{ - ProbeHandler: v1.ProbeHandler{ - Exec: &v1.ExecAction{Command: []string{"/bin/healthy.sh"}}, - }, - InitialDelaySeconds: 600, - TimeoutSeconds: 0, - PeriodSeconds: 60, - SuccessThreshold: 0, - FailureThreshold: 0, - } - } - } - if l.Spec.FluentdSpec.ReadinessDefaultCheck.BufferFreeSpace { - if l.Spec.FluentdSpec.ReadinessDefaultCheck.BufferFreeSpaceThreshold == 0 { - l.Spec.FluentdSpec.ReadinessDefaultCheck.BufferFreeSpaceThreshold = 90 - } - } - - if l.Spec.FluentdSpec.ReadinessDefaultCheck.BufferFileNumber { - if l.Spec.FluentdSpec.ReadinessDefaultCheck.BufferFileNumberMax == 0 { - l.Spec.FluentdSpec.ReadinessDefaultCheck.BufferFileNumberMax = 5000 - } - } - if l.Spec.FluentdSpec.ReadinessDefaultCheck.InitialDelaySeconds == 0 { - l.Spec.FluentdSpec.ReadinessDefaultCheck.InitialDelaySeconds = 5 - } - if l.Spec.FluentdSpec.ReadinessDefaultCheck.TimeoutSeconds == 0 { - l.Spec.FluentdSpec.ReadinessDefaultCheck.TimeoutSeconds = 3 - } - if l.Spec.FluentdSpec.ReadinessDefaultCheck.PeriodSeconds == 0 { - l.Spec.FluentdSpec.ReadinessDefaultCheck.PeriodSeconds = 30 - } - if l.Spec.FluentdSpec.ReadinessDefaultCheck.SuccessThreshold == 0 { - l.Spec.FluentdSpec.ReadinessDefaultCheck.SuccessThreshold = 3 - } - if l.Spec.FluentdSpec.ReadinessDefaultCheck.FailureThreshold == 0 { - l.Spec.FluentdSpec.ReadinessDefaultCheck.FailureThreshold = 1 - } - for i := range l.Spec.FluentdSpec.ExtraVolumes { - e := &l.Spec.FluentdSpec.ExtraVolumes[i] - if e.ContainerName == "" { - e.ContainerName = "fluentd" - } - if e.VolumeName == "" { - e.VolumeName = fmt.Sprintf("extravolume-%d", i) - } - if e.Path == "" { - e.Path = "/tmp" - } - if e.Volume == nil { - e.Volume = &volume.KubernetesVolume{} - } - } - if l.Spec.ConfigCheck.TimeoutSeconds == 0 { - l.Spec.ConfigCheck.TimeoutSeconds = 10 + if len(l.Status.FluentdConfigName) == 0 { + if err := l.Spec.FluentdSpec.SetDefaults(); err != nil { + return err } } - + if l.Spec.ConfigCheck.TimeoutSeconds == 0 { + l.Spec.ConfigCheck.TimeoutSeconds = 10 + } if l.Spec.SyslogNGSpec != nil { // if l.Spec.SyslogNGSpec.MaxConnections == 0 { // max connections is now configured dynamically if not set @@ -701,11 +462,11 @@ func persistentVolumeModePointer(mode v1.PersistentVolumeMode) *v1.PersistentVol } // FluentdObjectMeta creates an objectMeta for resource fluentd -func (l *Logging) FluentdObjectMeta(name, component string) metav1.ObjectMeta { +func (l *Logging) FluentdObjectMeta(name, component string, f FluentdSpec) metav1.ObjectMeta { o := metav1.ObjectMeta{ Name: l.QualifiedName(name), Namespace: l.Spec.ControlNamespace, - Labels: l.GetFluentdLabels(component), + Labels: l.GetFluentdLabels(component, f), OwnerReferences: []metav1.OwnerReference{ { APIVersion: l.APIVersion, @@ -719,9 +480,9 @@ func (l *Logging) FluentdObjectMeta(name, component string) metav1.ObjectMeta { return o } -func (l *Logging) GetFluentdLabels(component string) map[string]string { +func (l *Logging) GetFluentdLabels(component string, f FluentdSpec) map[string]string { return util.MergeLabels( - l.Spec.FluentdSpec.Labels, + f.Labels, map[string]string{ "app.kubernetes.io/name": "fluentd", "app.kubernetes.io/component": component, @@ -763,14 +524,6 @@ func GenerateLoggingRefLabels(loggingRef string) map[string]string { return map[string]string{"app.kubernetes.io/managed-by": loggingRef} } -// GetFluentdMetricsPath returns the right Fluentd metrics endpoint -// depending on the number of workers and the user configuration -func (l *Logging) GetFluentdMetricsPath() string { - if l.Spec.FluentdSpec.Metrics.Path == "" { - if l.Spec.FluentdSpec.Workers > 1 { - return "/aggregated_metrics" - } - return "/metrics" - } - return l.Spec.FluentdSpec.Metrics.Path +func (l *Logging) AreMultipleAggregatorsSet() bool { + return l.Spec.SyslogNGSpec != nil && (l.Spec.FluentdSpec != nil || len(l.Status.FluentdConfigName) != 0) } diff --git a/pkg/sdk/logging/api/v1beta1/zz_generated.deepcopy.go b/pkg/sdk/logging/api/v1beta1/zz_generated.deepcopy.go index c45b639ee..97360b7bb 100644 --- a/pkg/sdk/logging/api/v1beta1/zz_generated.deepcopy.go +++ b/pkg/sdk/logging/api/v1beta1/zz_generated.deepcopy.go @@ -1302,6 +1302,90 @@ func (in *FluentbitTLS) DeepCopy() *FluentbitTLS { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FluentdConfig) DeepCopyInto(out *FluentdConfig) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FluentdConfig. +func (in *FluentdConfig) DeepCopy() *FluentdConfig { + if in == nil { + return nil + } + out := new(FluentdConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FluentdConfig) 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 *FluentdConfigList) DeepCopyInto(out *FluentdConfigList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]FluentdConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FluentdConfigList. +func (in *FluentdConfigList) DeepCopy() *FluentdConfigList { + if in == nil { + return nil + } + out := new(FluentdConfigList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *FluentdConfigList) 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 *FluentdConfigStatus) DeepCopyInto(out *FluentdConfigStatus) { + *out = *in + if in.Active != nil { + in, out := &in.Active, &out.Active + *out = new(bool) + **out = **in + } + if in.Problems != nil { + in, out := &in.Problems, &out.Problems + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FluentdConfigStatus. +func (in *FluentdConfigStatus) DeepCopy() *FluentdConfigStatus { + if in == nil { + return nil + } + out := new(FluentdConfigStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FluentdDrainConfig) DeepCopyInto(out *FluentdDrainConfig) { *out = *in