diff --git a/build/Dockerfile b/build/Dockerfile index c07770ce3..8cff2c7c4 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -53,5 +53,6 @@ COPY build/init-entrypoint.sh /init-entrypoint.sh COPY build/ps-entry.sh /ps-entry.sh COPY build/physical-restore-ps-entry.sh /physical-restore-ps-entry.sh COPY build/pbm-entry.sh /pbm-entry.sh +COPY build/logcollector /logcollector USER 2 diff --git a/build/init-entrypoint.sh b/build/init-entrypoint.sh index c36a17446..ec1e05f6c 100755 --- a/build/init-entrypoint.sh +++ b/build/init-entrypoint.sh @@ -6,4 +6,7 @@ set -o xtrace install -o "$(id -u)" -g "$(id -g)" -m 0755 -D /ps-entry.sh /opt/percona/ps-entry.sh install -o "$(id -u)" -g "$(id -g)" -m 0755 -D /physical-restore-ps-entry.sh /opt/percona/physical-restore-ps-entry.sh install -o "$(id -u)" -g "$(id -g)" -m 0755 -D /mongodb-healthcheck /opt/percona/mongodb-healthcheck -install -o "$(id -u)" -g "$(id -g)" -m 0755 -D /pbm-entry.sh /opt/percona/pbm-entry.sh \ No newline at end of file +install -o "$(id -u)" -g "$(id -g)" -m 0755 -D /pbm-entry.sh /opt/percona/pbm-entry.sh +cp -a /logcollector /opt/percona/ +chown -R "$(id -u)":"$(id -g)" /opt/percona/logcollector +chmod -R 0755 /opt/percona/logcollector diff --git a/build/logcollector/entrypoint.sh b/build/logcollector/entrypoint.sh new file mode 100755 index 000000000..a601fe620 --- /dev/null +++ b/build/logcollector/entrypoint.sh @@ -0,0 +1,21 @@ +#!/bin/sh +set -e +set -o xtrace + +export PATH="$PATH":/opt/fluent-bit/bin + +if [ "$1" = 'logrotate' ]; then + if [[ $EUID != 1001 ]]; then + # logrotate requires UID in /etc/passwd + sed -e "s^x:1001:^x:$EUID:^" /etc/passwd >/tmp/passwd + cat /tmp/passwd >/etc/passwd + rm -rf /tmp/passwd + fi + exec go-cron "0 0 * * *" sh -c "logrotate -s /data/logs/logrotate.status /opt/percona/logcollector/logrotate/logrotate.conf;/usr/bin/find /data/logs/ -mtime +7 ! -name logrotate.status -delete" +else + if [ "$1" = 'fluent-bit' ]; then + fluentbit_opt+='-c /opt/percona/logcollector/fluentbit/fluentbit.conf' + fi + + exec "$@" $fluentbit_opt +fi diff --git a/build/logcollector/fluentbit/custom/default.conf b/build/logcollector/fluentbit/custom/default.conf new file mode 100644 index 000000000..e69de29bb diff --git a/build/logcollector/fluentbit/fluentbit.conf b/build/logcollector/fluentbit/fluentbit.conf new file mode 100644 index 000000000..75ff9d06f --- /dev/null +++ b/build/logcollector/fluentbit/fluentbit.conf @@ -0,0 +1,2 @@ +@INCLUDE fluentbit_*.conf +@INCLUDE custom/*.conf diff --git a/build/logcollector/fluentbit/fluentbit_mongo.conf b/build/logcollector/fluentbit/fluentbit_mongo.conf new file mode 100644 index 000000000..beb8ab407 --- /dev/null +++ b/build/logcollector/fluentbit/fluentbit_mongo.conf @@ -0,0 +1,25 @@ +[SERVICE] + Flush 1 + Log_Level error + Daemon off + +[INPUT] + Name tail + Path ${LOG_DATA_DIR}/mongod.log + Tag ${POD_NAMESPACE}.${POD_NAME}.mongod.log + Refresh_Interval 5 + DB /tmp/flb_kube.db + read_from_head true + Path_Key file + +[OUTPUT] + Name stdout + Match * + Format json_lines + json_date_key false + +[OUTPUT] + Name file + Match ${POD_NAMESPACE}.${POD_NAME}.mongod.log + File mongod.full.log + Path ${LOG_DATA_DIR}/ diff --git a/build/logcollector/fluentbit/parsers_multiline.conf b/build/logcollector/fluentbit/parsers_multiline.conf new file mode 100644 index 000000000..7409846f7 --- /dev/null +++ b/build/logcollector/fluentbit/parsers_multiline.conf @@ -0,0 +1,17 @@ +[MULTILINE_PARSER] + name multiline-regex-test + type regex + flush_timeout 1000 + # + # Regex rules for multiline parsing + # --------------------------------- + # + # configuration hints: + # + # - first state always has the name: start_state + # - every field in the rule must be inside double quotes + # + # rules | state name | regex pattern | next state + # ------|---------------|-------------------------------------------- + rule "start_state" "/\d{2,4}\-\d{2,4}\-\d{2,4}T\d{2,4}\:\d{2,4}\:\d{2,4}\.\d{1,6}Z(.*)|\d{2,6} \d{2,4}\:\d{2,4}\:\d{2,4}(.*)/" "cont" + rule "cont" "/^\D/" "cont" diff --git a/build/logcollector/logrotate/logrotate.conf b/build/logcollector/logrotate/logrotate.conf new file mode 100644 index 000000000..aab10cea6 --- /dev/null +++ b/build/logcollector/logrotate/logrotate.conf @@ -0,0 +1,10 @@ +/data/logs/*.log { + daily + minsize 10M + maxsize 100M + rotate 10 + missingok + nocompress + notifempty + sharedscripts +} diff --git a/build/ps-entry.sh b/build/ps-entry.sh index 98c4efe54..82e2d73ee 100755 --- a/build/ps-entry.sh +++ b/build/ps-entry.sh @@ -480,6 +480,11 @@ if [[ $originalArgOne == mongo* ]]; then _mongod_hack_rename_arg_save_val --sslDisabledProtocols --tlsDisabledProtocols "${mongodHackedArgs[@]}" fi + if [[ $originalArgOne == "mongod" && "${LOGCOLLECTOR_ENABLED:-}" == "true" ]]; then + _mongod_hack_ensure_arg_val --logpath "/data/logs/mongod.log" "${mongodHackedArgs[@]}" + _mongod_hack_ensure_arg --logappend "${mongodHackedArgs[@]}" + fi + set -- "${mongodHackedArgs[@]}" # MongoDB 3.6+ defaults to localhost-only binding diff --git a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml index 2bc2c8fa1..9fc840a78 100644 --- a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml +++ b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml @@ -534,6 +534,122 @@ spec: type: object initImage: type: string + logcollector: + properties: + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + 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 + enabled: + type: boolean + image: + type: string + imagePullPolicy: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + 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 + type: object multiCluster: properties: DNSSuffix: diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index 4312065d7..f48adc09a 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -1247,6 +1247,122 @@ spec: type: object initImage: type: string + logcollector: + properties: + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + 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 + enabled: + type: boolean + image: + type: string + imagePullPolicy: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + 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 + type: object multiCluster: properties: DNSSuffix: diff --git a/deploy/cr.yaml b/deploy/cr.yaml index 13d2858c5..8640e0472 100644 --- a/deploy/cr.yaml +++ b/deploy/cr.yaml @@ -743,3 +743,10 @@ spec: # storageName: s3-us-west # compressionType: gzip # compressionLevel: 6 + logcollector: + enabled: true + image: perconalab/percona-xtradb-cluster-operator:main-logcollector + resources: + requests: + memory: 100M + cpu: 200m diff --git a/deploy/crd.yaml b/deploy/crd.yaml index b41742a74..f06ccdfab 100644 --- a/deploy/crd.yaml +++ b/deploy/crd.yaml @@ -1247,6 +1247,122 @@ spec: type: object initImage: type: string + logcollector: + properties: + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + 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 + enabled: + type: boolean + image: + type: string + imagePullPolicy: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + 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 + type: object multiCluster: properties: DNSSuffix: diff --git a/deploy/cw-bundle.yaml b/deploy/cw-bundle.yaml index debf6c4f9..a5297950c 100644 --- a/deploy/cw-bundle.yaml +++ b/deploy/cw-bundle.yaml @@ -1247,6 +1247,122 @@ spec: type: object initImage: type: string + logcollector: + properties: + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + 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 + enabled: + type: boolean + image: + type: string + imagePullPolicy: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + 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 + type: object multiCluster: properties: DNSSuffix: diff --git a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-cfg-oc.yml b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-cfg-oc.yml index 0720b9596..3529e731a 100644 --- a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-cfg-oc.yml +++ b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-cfg-oc.yml @@ -141,6 +141,8 @@ spec: name: config - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: monitoring-pmm3-mongodb-encryption-key readOnly: true @@ -329,3 +331,13 @@ spec: storage: 3Gi status: phase: Pending + - metadata: + name: mongod-data-logs + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 3Gi + status: + phase: Pending diff --git a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-cfg.yml b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-cfg.yml index e73c9939e..84b595828 100644 --- a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-cfg.yml +++ b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-cfg.yml @@ -142,6 +142,8 @@ spec: name: config - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: monitoring-pmm3-mongodb-encryption-key readOnly: true @@ -331,3 +333,13 @@ spec: storage: 3Gi status: phase: Pending + - metadata: + name: mongod-data-logs + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 3Gi + status: + phase: Pending diff --git a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-no-pmm-oc.yml b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-no-pmm-oc.yml index 73ca5e0e8..c575b8569 100644 --- a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-no-pmm-oc.yml +++ b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-no-pmm-oc.yml @@ -129,6 +129,8 @@ spec: name: config - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: monitoring-pmm3-mongodb-encryption-key readOnly: true @@ -200,3 +202,13 @@ spec: storage: 1Gi status: phase: Pending + - metadata: + name: mongod-data-logs + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + status: + phase: Pending diff --git a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-no-pmm.yml b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-no-pmm.yml index 6247c9542..351b7f49d 100644 --- a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-no-pmm.yml +++ b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-no-pmm.yml @@ -130,6 +130,8 @@ spec: name: config - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: monitoring-pmm3-mongodb-encryption-key readOnly: true @@ -202,3 +204,13 @@ spec: storage: 1Gi status: phase: Pending + - metadata: + name: mongod-data-logs + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + status: + phase: Pending diff --git a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-oc.yml b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-oc.yml index 5fcc35f41..1f79bfba4 100644 --- a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-oc.yml +++ b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0-oc.yml @@ -129,6 +129,8 @@ spec: name: config - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: monitoring-pmm3-mongodb-encryption-key readOnly: true @@ -317,3 +319,13 @@ spec: storage: 1Gi status: phase: Pending + - metadata: + name: mongod-data-logs + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + status: + phase: Pending diff --git a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0.yml b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0.yml index daa7b4caf..11c5104cb 100644 --- a/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0.yml +++ b/e2e-tests/monitoring-pmm3/compare/statefulset_monitoring-pmm3-rs0.yml @@ -130,6 +130,8 @@ spec: name: config - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: monitoring-pmm3-mongodb-encryption-key readOnly: true @@ -319,3 +321,13 @@ spec: storage: 1Gi status: phase: Pending + - metadata: + name: mongod-data-logs + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + status: + phase: Pending diff --git a/e2e-tests/version-service/conf/crd.yaml b/e2e-tests/version-service/conf/crd.yaml index b41742a74..f06ccdfab 100644 --- a/e2e-tests/version-service/conf/crd.yaml +++ b/e2e-tests/version-service/conf/crd.yaml @@ -1247,6 +1247,122 @@ spec: type: object initImage: type: string + logcollector: + properties: + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + 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 + enabled: + type: boolean + image: + type: string + imagePullPolicy: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + request: + 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 + type: object multiCluster: properties: DNSSuffix: diff --git a/pkg/apis/psmdb/v1/psmdb_types.go b/pkg/apis/psmdb/v1/psmdb_types.go index f36c9e519..da7a53d8c 100644 --- a/pkg/apis/psmdb/v1/psmdb_types.go +++ b/pkg/apis/psmdb/v1/psmdb_types.go @@ -97,6 +97,7 @@ type PerconaServerMongoDBSpec struct { Users []User `json:"users,omitempty"` Roles []Role `json:"roles,omitempty"` VolumeExpansionEnabled bool `json:"enableVolumeExpansion,omitempty"` + LogCollector *LogCollectorSpec `json:"logcollector,omitempty"` } type UserRole struct { @@ -1356,3 +1357,18 @@ func (cr *PerconaServerMongoDB) PBMResyncInProgress() bool { v, ok := cr.Annotations[AnnotationResyncInProgress] return ok && v != "" } + +// LogCollectorSpec defines the configuration for enabling and customizing +// the log collection component that stores logs in a PVC. +type LogCollectorSpec struct { + Enabled bool `json:"enabled,omitempty"` + Image string `json:"image,omitempty"` + Resources corev1.ResourceRequirements `json:"resources,omitempty"` + Configuration string `json:"configuration,omitempty"` + ContainerSecurityContext *corev1.SecurityContext `json:"containerSecurityContext,omitempty"` + ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` +} + +func (cr *PerconaServerMongoDB) IsLogCollectorEnabled() bool { + return cr.Spec.LogCollector != nil && cr.Spec.LogCollector.Enabled +} diff --git a/pkg/apis/psmdb/v1/zz_generated.deepcopy.go b/pkg/apis/psmdb/v1/zz_generated.deepcopy.go index d77375368..f6150cb82 100644 --- a/pkg/apis/psmdb/v1/zz_generated.deepcopy.go +++ b/pkg/apis/psmdb/v1/zz_generated.deepcopy.go @@ -451,6 +451,27 @@ func (in *LivenessProbeExtended) DeepCopy() *LivenessProbeExtended { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LogCollectorSpec) DeepCopyInto(out *LogCollectorSpec) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + if in.ContainerSecurityContext != nil { + in, out := &in.ContainerSecurityContext, &out.ContainerSecurityContext + *out = new(corev1.SecurityContext) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LogCollectorSpec. +func (in *LogCollectorSpec) DeepCopy() *LogCollectorSpec { + if in == nil { + return nil + } + out := new(LogCollectorSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MongodSpecInMemory) DeepCopyInto(out *MongodSpecInMemory) { *out = *in @@ -1347,6 +1368,11 @@ func (in *PerconaServerMongoDBSpec) DeepCopyInto(out *PerconaServerMongoDBSpec) (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.LogCollector != nil { + in, out := &in.LogCollector, &out.LogCollector + *out = new(LogCollectorSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PerconaServerMongoDBSpec. diff --git a/pkg/controller/perconaservermongodb/psmdb_controller.go b/pkg/controller/perconaservermongodb/psmdb_controller.go index 500f05c0f..7d4601152 100644 --- a/pkg/controller/perconaservermongodb/psmdb_controller.go +++ b/pkg/controller/perconaservermongodb/psmdb_controller.go @@ -46,8 +46,6 @@ import ( "github.com/percona/percona-server-mongodb-operator/pkg/version" ) -var secretFileMode int32 = 288 - // Add creates a new PerconaServerMongoDB Controller and adds it to the Manager. The Manager will set fields on the Controller // and Start it when the Manager is Started. func Add(mgr manager.Manager) error { diff --git a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-arbiter.yaml b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-arbiter.yaml index 6567f52ef..03ff7e953 100644 --- a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-arbiter.yaml +++ b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-arbiter.yaml @@ -79,6 +79,8 @@ spec: value: "27017" - name: MONGODB_REPLSET value: cfg + - name: LOGCOLLECTOR_ENABLED + value: "true" envFrom: - secretRef: name: internal-reconcile-statefulset-cr-users @@ -144,6 +146,8 @@ spec: readOnly: true - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: my-cluster-name-mongodb-encryption-key readOnly: true @@ -201,6 +205,43 @@ spec: readOnly: true - mountPath: /data/db name: mongod-data + - name: logs + image: perconalab/percona-xtradb-cluster-operator:main-logcollector + command: [ "/opt/percona/logcollector/entrypoint.sh" ] + args: [ "fluent-bit" ] + env: + - name: LOG_DATA_DIR + value: /data/logs + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + resources: + requests: + cpu: 200m + memory: 100M + volumeMounts: + - mountPath: /data/logs + name: mongod-data-logs + - mountPath: /opt/percona + name: bin + - name: logrotate + image: perconalab/percona-xtradb-cluster-operator:main-logcollector + command: [ "/opt/percona/logcollector/entrypoint.sh" ] + args: [ "logrotate" ] + resources: + requests: + cpu: 200m + memory: 100M + volumeMounts: + - mountPath: /data/logs + name: mongod-data-logs + - mountPath: /opt/percona + name: bin initContainers: - command: - /init-entrypoint.sh @@ -264,4 +305,15 @@ spec: resources: requests: storage: 3Gi + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: mongod-data-logs + namespace: reconcile-statefulset + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 3Gi status: {} diff --git a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-mongod.yaml b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-mongod.yaml index 6567f52ef..03ff7e953 100644 --- a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-mongod.yaml +++ b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-mongod.yaml @@ -79,6 +79,8 @@ spec: value: "27017" - name: MONGODB_REPLSET value: cfg + - name: LOGCOLLECTOR_ENABLED + value: "true" envFrom: - secretRef: name: internal-reconcile-statefulset-cr-users @@ -144,6 +146,8 @@ spec: readOnly: true - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: my-cluster-name-mongodb-encryption-key readOnly: true @@ -201,6 +205,43 @@ spec: readOnly: true - mountPath: /data/db name: mongod-data + - name: logs + image: perconalab/percona-xtradb-cluster-operator:main-logcollector + command: [ "/opt/percona/logcollector/entrypoint.sh" ] + args: [ "fluent-bit" ] + env: + - name: LOG_DATA_DIR + value: /data/logs + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + resources: + requests: + cpu: 200m + memory: 100M + volumeMounts: + - mountPath: /data/logs + name: mongod-data-logs + - mountPath: /opt/percona + name: bin + - name: logrotate + image: perconalab/percona-xtradb-cluster-operator:main-logcollector + command: [ "/opt/percona/logcollector/entrypoint.sh" ] + args: [ "logrotate" ] + resources: + requests: + cpu: 200m + memory: 100M + volumeMounts: + - mountPath: /data/logs + name: mongod-data-logs + - mountPath: /opt/percona + name: bin initContainers: - command: - /init-entrypoint.sh @@ -264,4 +305,15 @@ spec: resources: requests: storage: 3Gi + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: mongod-data-logs + namespace: reconcile-statefulset + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 3Gi status: {} diff --git a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-nv.yaml b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-nv.yaml index 6567f52ef..03ff7e953 100644 --- a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-nv.yaml +++ b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/cfg-nv.yaml @@ -79,6 +79,8 @@ spec: value: "27017" - name: MONGODB_REPLSET value: cfg + - name: LOGCOLLECTOR_ENABLED + value: "true" envFrom: - secretRef: name: internal-reconcile-statefulset-cr-users @@ -144,6 +146,8 @@ spec: readOnly: true - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: my-cluster-name-mongodb-encryption-key readOnly: true @@ -201,6 +205,43 @@ spec: readOnly: true - mountPath: /data/db name: mongod-data + - name: logs + image: perconalab/percona-xtradb-cluster-operator:main-logcollector + command: [ "/opt/percona/logcollector/entrypoint.sh" ] + args: [ "fluent-bit" ] + env: + - name: LOG_DATA_DIR + value: /data/logs + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + resources: + requests: + cpu: 200m + memory: 100M + volumeMounts: + - mountPath: /data/logs + name: mongod-data-logs + - mountPath: /opt/percona + name: bin + - name: logrotate + image: perconalab/percona-xtradb-cluster-operator:main-logcollector + command: [ "/opt/percona/logcollector/entrypoint.sh" ] + args: [ "logrotate" ] + resources: + requests: + cpu: 200m + memory: 100M + volumeMounts: + - mountPath: /data/logs + name: mongod-data-logs + - mountPath: /opt/percona + name: bin initContainers: - command: - /init-entrypoint.sh @@ -264,4 +305,15 @@ spec: resources: requests: storage: 3Gi + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: mongod-data-logs + namespace: reconcile-statefulset + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 3Gi status: {} diff --git a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-arbiter.yaml b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-arbiter.yaml index 68597bedd..5e6e09766 100644 --- a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-arbiter.yaml +++ b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-arbiter.yaml @@ -79,6 +79,8 @@ spec: value: "27017" - name: MONGODB_REPLSET value: rs0 + - name: LOGCOLLECTOR_ENABLED + value: "true" envFrom: - secretRef: name: internal-reconcile-statefulset-cr-users @@ -145,6 +147,8 @@ spec: readOnly: true - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: my-cluster-name-mongodb-encryption-key readOnly: true @@ -200,5 +204,7 @@ spec: secretName: internal-reconcile-statefulset-cr-users - emptyDir: {} name: mongod-data + - emptyDir: { } + name: mongod-data-logs updateStrategy: type: OnDelete diff --git a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-mongod.yaml b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-mongod.yaml index f0e28a4f5..851fe2d85 100644 --- a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-mongod.yaml +++ b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-mongod.yaml @@ -79,6 +79,8 @@ spec: value: "27017" - name: MONGODB_REPLSET value: rs0 + - name: LOGCOLLECTOR_ENABLED + value: "true" envFrom: - secretRef: name: internal-reconcile-statefulset-cr-users @@ -144,6 +146,8 @@ spec: readOnly: true - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: my-cluster-name-mongodb-encryption-key readOnly: true @@ -201,6 +205,43 @@ spec: readOnly: true - mountPath: /data/db name: mongod-data + - name: logs + image: perconalab/percona-xtradb-cluster-operator:main-logcollector + command: [ "/opt/percona/logcollector/entrypoint.sh" ] + args: [ "fluent-bit" ] + env: + - name: LOG_DATA_DIR + value: /data/logs + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + resources: + requests: + cpu: 200m + memory: 100M + volumeMounts: + - mountPath: /data/logs + name: mongod-data-logs + - mountPath: /opt/percona + name: bin + - name: logrotate + image: perconalab/percona-xtradb-cluster-operator:main-logcollector + command: [ "/opt/percona/logcollector/entrypoint.sh" ] + args: [ "logrotate" ] + resources: + requests: + cpu: 200m + memory: 100M + volumeMounts: + - mountPath: /data/logs + name: mongod-data-logs + - mountPath: /opt/percona + name: bin initContainers: - command: - /init-entrypoint.sh @@ -264,3 +305,14 @@ spec: resources: requests: storage: 3Gi + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: mongod-data-logs + namespace: reconcile-statefulset + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 3Gi diff --git a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-nv.yaml b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-nv.yaml index 17dc3e568..49e76382c 100644 --- a/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-nv.yaml +++ b/pkg/controller/perconaservermongodb/testdata/reconcile-statefulset/rs0-nv.yaml @@ -79,6 +79,8 @@ spec: value: "27017" - name: MONGODB_REPLSET value: rs0 + - name: LOGCOLLECTOR_ENABLED + value: "true" envFrom: - secretRef: name: internal-reconcile-statefulset-cr-users @@ -143,6 +145,8 @@ spec: readOnly: true - mountPath: /opt/percona name: bin + - mountPath: /data/logs + name: mongod-data-logs - mountPath: /etc/mongodb-encryption name: my-cluster-name-mongodb-encryption-key readOnly: true @@ -200,6 +204,43 @@ spec: readOnly: true - mountPath: /data/db name: mongod-data + - name: logs + image: perconalab/percona-xtradb-cluster-operator:main-logcollector + command: [ "/opt/percona/logcollector/entrypoint.sh" ] + args: [ "fluent-bit" ] + env: + - name: LOG_DATA_DIR + value: /data/logs + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + resources: + requests: + cpu: 200m + memory: 100M + volumeMounts: + - mountPath: /data/logs + name: mongod-data-logs + - mountPath: /opt/percona + name: bin + - name: logrotate + image: perconalab/percona-xtradb-cluster-operator:main-logcollector + command: [ "/opt/percona/logcollector/entrypoint.sh" ] + args: [ "logrotate" ] + resources: + requests: + cpu: 200m + memory: 100M + volumeMounts: + - mountPath: /data/logs + name: mongod-data-logs + - mountPath: /opt/percona + name: bin initContainers: - command: - /init-entrypoint.sh @@ -263,3 +304,14 @@ spec: resources: requests: storage: 3Gi + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: mongod-data-logs + namespace: reconcile-statefulset + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 3Gi diff --git a/pkg/psmdb/config/const.go b/pkg/psmdb/config/const.go index 3f4dbbe56..386e086ea 100644 --- a/pkg/psmdb/config/const.go +++ b/pkg/psmdb/config/const.go @@ -15,12 +15,14 @@ const ( MinWiredTigerCacheSizeGB float64 = 0.25 // MongodDataVolClaimName is a PVC Claim name - MongodDataVolClaimName = "mongod-data" + MongodDataVolClaimName = "mongod-data" + MongodDataLogsVolClaimName = "mongod-data-logs" // MongodContainerDataDir is a mongo data path in container MongodContainerDataDir = "/data/db" - - BinVolumeName = "bin" - BinMountPath = "/opt/percona" + // MongodContainerDataLogsDir is a mongo data path in container for logs. + MongodContainerDataLogsDir = "/data/logs" + BinVolumeName = "bin" + BinMountPath = "/opt/percona" LDAPConfVolClaimName = "ldap" LDAPConfDir = "/etc/openldap" diff --git a/pkg/psmdb/container.go b/pkg/psmdb/container.go index 27ebc11e6..51592ff0e 100644 --- a/pkg/psmdb/container.go +++ b/pkg/psmdb/container.go @@ -66,6 +66,13 @@ func container(ctx context.Context, cr *api.PerconaServerMongoDB, replset *api.R }...) } + if cr.CompareVersion("1.21.0") >= 0 { + volumes = append(volumes, corev1.VolumeMount{ + Name: config.MongodDataLogsVolClaimName, + MountPath: config.MongodContainerDataLogsDir, + }) + } + encryptionEnabled, err := isEncryptionEnabled(cr, replset) if err != nil { return corev1.Container{}, err @@ -168,6 +175,15 @@ func container(ctx context.Context, cr *api.PerconaServerMongoDB, replset *api.R container.Command = []string{config.BinMountPath + "/ps-entry.sh"} } + if cr.CompareVersion("1.21.0") >= 0 { + if cr.IsLogCollectorEnabled() { + container.Env = append(container.Env, corev1.EnvVar{ + Name: "LOGCOLLECTOR_ENABLED", + Value: "true", + }) + } + } + return container, nil } diff --git a/pkg/psmdb/logcollector/container.go b/pkg/psmdb/logcollector/container.go new file mode 100644 index 000000000..7d6ca7682 --- /dev/null +++ b/pkg/psmdb/logcollector/container.go @@ -0,0 +1,117 @@ +package logcollector + +import ( + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + + api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" + "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/config" +) + +func Containers(cr *api.PerconaServerMongoDB) ([]corev1.Container, error) { + if cr.Spec.LogCollector == nil || !cr.Spec.LogCollector.Enabled { + return nil, nil + } + + logCont, err := logContainer(cr) + if err != nil { + return nil, err + } + + logRotationCont, err := logRotationContainer(cr) + if err != nil { + return nil, err + } + + return []corev1.Container{*logCont, *logRotationCont}, nil +} + +func logContainer(cr *api.PerconaServerMongoDB) (*corev1.Container, error) { + if cr.Spec.LogCollector == nil { + return nil, errors.New("logcollector can't be nil") + } + + envs := []corev1.EnvVar{ + { + Name: "LOG_DATA_DIR", + Value: config.MongodContainerDataLogsDir, + }, + { + Name: "POD_NAMESPACE", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.namespace", + }, + }, + }, + { + Name: "POD_NAME", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.name", + }, + }, + }, + } + + container := corev1.Container{ + Name: "logs", + Image: cr.Spec.LogCollector.Image, + ImagePullPolicy: cr.Spec.LogCollector.ImagePullPolicy, + Env: envs, + Args: []string{ + "fluent-bit", + }, + Command: []string{"/opt/percona/logcollector/entrypoint.sh"}, + SecurityContext: cr.Spec.LogCollector.ContainerSecurityContext, + Resources: cr.Spec.LogCollector.Resources, + VolumeMounts: []corev1.VolumeMount{ + { + Name: config.MongodDataLogsVolClaimName, + MountPath: config.MongodContainerDataLogsDir, + }, + { + Name: config.BinVolumeName, + MountPath: config.BinMountPath, + }, + }, + } + + return &container, nil +} + +func logRotationContainer(cr *api.PerconaServerMongoDB) (*corev1.Container, error) { + if cr.Spec.LogCollector == nil { + return nil, errors.New("logcollector can't be nil") + } + + container := corev1.Container{ + Name: "logrotate", + Image: cr.Spec.LogCollector.Image, + ImagePullPolicy: cr.Spec.LogCollector.ImagePullPolicy, + SecurityContext: cr.Spec.LogCollector.ContainerSecurityContext, + Resources: cr.Spec.LogCollector.Resources, + Args: []string{ + "logrotate", + }, + Command: []string{"/opt/percona/logcollector/entrypoint.sh"}, + VolumeMounts: []corev1.VolumeMount{ + { + Name: config.MongodDataLogsVolClaimName, + MountPath: config.MongodContainerDataLogsDir, + }, + { + Name: config.BinVolumeName, + MountPath: config.BinMountPath, + }, + }, + } + + if cr.Spec.LogCollector.Configuration != "" { + container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{ + Name: "logcollector-config", + MountPath: "/etc/fluentbit/custom", + }) + } + return &container, nil +} diff --git a/pkg/psmdb/logcollector/container_test.go b/pkg/psmdb/logcollector/container_test.go new file mode 100644 index 000000000..8699259ac --- /dev/null +++ b/pkg/psmdb/logcollector/container_test.go @@ -0,0 +1,56 @@ +package logcollector + +import ( + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" +) + +func TestContainers(t *testing.T) { + tests := map[string]struct { + logCollector *api.LogCollectorSpec + expectedContainerNames []string + }{ + "nil logcollector": {}, + "logcollector disabled": { + logCollector: &api.LogCollectorSpec{ + Enabled: false, + }, + }, + "logcollector enabled": { + logCollector: &api.LogCollectorSpec{ + Enabled: true, + Image: "test-image", + ImagePullPolicy: corev1.PullIfNotPresent, + }, + expectedContainerNames: []string{"logs", "logrotate"}, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + cr := &api.PerconaServerMongoDB{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster", + Namespace: "default", + }, + Spec: api.PerconaServerMongoDBSpec{ + LogCollector: tt.logCollector, + }, + } + + containers, err := Containers(cr) + assert.NoError(t, err) + + var gotNames []string + for _, c := range containers { + gotNames = append(gotNames, c.Name) + } + assert.Equal(t, tt.expectedContainerNames, gotNames) + }) + } +} diff --git a/pkg/psmdb/statefulset.go b/pkg/psmdb/statefulset.go index 7dd83d35d..caa5c2d6b 100644 --- a/pkg/psmdb/statefulset.go +++ b/pkg/psmdb/statefulset.go @@ -14,6 +14,7 @@ import ( api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" "github.com/percona/percona-server-mongodb-operator/pkg/naming" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/config" + "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/logcollector" "github.com/percona/percona-server-mongodb-operator/pkg/psmdb/pmm" ) @@ -238,27 +239,45 @@ func StatefulSpec(ctx context.Context, cr *api.PerconaServerMongoDB, replset *ap if ls[naming.LabelKubernetesComponent] == "arbiter" { volumes = append(volumes, - corev1.Volume{ - Name: config.MongodDataVolClaimName, - VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, + []corev1.Volume{ + { + Name: config.MongodDataVolClaimName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, }, - }, + { + Name: config.MongodDataLogsVolClaimName, + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + }..., ) } else { if volumeSpec.PersistentVolumeClaim.PersistentVolumeClaimSpec != nil { volumeClaimTemplates = []corev1.PersistentVolumeClaim{ PersistentVolumeClaim(config.MongodDataVolClaimName, cr.Namespace, volumeSpec), + PersistentVolumeClaim(config.MongodDataLogsVolClaimName, cr.Namespace, volumeSpec), } } else { volumes = append(volumes, - corev1.Volume{ - Name: config.MongodDataVolClaimName, - VolumeSource: corev1.VolumeSource{ - HostPath: volumeSpec.HostPath, - EmptyDir: volumeSpec.EmptyDir, + []corev1.Volume{ + { + Name: config.MongodDataVolClaimName, + VolumeSource: corev1.VolumeSource{ + HostPath: volumeSpec.HostPath, + EmptyDir: volumeSpec.EmptyDir, + }, }, - }, + { + Name: config.MongodDataLogsVolClaimName, + VolumeSource: corev1.VolumeSource{ + HostPath: volumeSpec.HostPath, + EmptyDir: volumeSpec.EmptyDir, + }, + }, + }..., ) } @@ -274,6 +293,14 @@ func StatefulSpec(ctx context.Context, cr *api.PerconaServerMongoDB, replset *ap if pmmC != nil { containers = append(containers, *pmmC) } + + if cr.CompareVersion("1.21.0") >= 0 { + logCollectorCs, err := logcollector.Containers(cr) + if err != nil { + log.Error(err, "error preparing logcollector containers") + } + containers = append(containers, logCollectorCs...) + } } volumes = multiAZ.WithSidecarVolumes(logf.FromContext(ctx), volumes)