first commit
This commit is contained in:
8
templates/fluent-bit/NOTES.txt
Normal file
8
templates/fluent-bit/NOTES.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Thank you for installing the {{ .Chart.Name }} chart for the Amplify Integration Platform.
|
||||
|
||||
Your release is named {{ .Release.Name }}.
|
||||
|
||||
To learn more about the release, try:
|
||||
|
||||
$ helm status {{ .Release.Name }}
|
||||
$ helm get all {{ .Release.Name }}
|
||||
64
templates/fluent-bit/_helpers.tpl
Normal file
64
templates/fluent-bit/_helpers.tpl
Normal file
@@ -0,0 +1,64 @@
|
||||
{{- define "fluent-bit.name" -}}
|
||||
{{- default "fluent-bit" .Values.fluentBit.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "fluent-bit.appName" -}}
|
||||
{{- $name := default "fluent-bit" .Values.fluentBit.nameOverride -}}
|
||||
{{- $env := default "fluent-bit" .Values.global.appEnv -}}
|
||||
{{- printf "%s-%s" $name $env | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "fluent-bit.labels" -}}
|
||||
{{ include "dataplane.labels" . }}
|
||||
{{ include "fluent-bit.selectorLabels" . }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "fluent-bit.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "fluent-bit.name" . }}
|
||||
app: {{ include "fluent-bit.appName" . }}
|
||||
dplane: "fluent-bit"
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "fluent-bit.serviceAccountName" -}}
|
||||
{{- if .Values.fluentBit.serviceAccount.enabled -}}
|
||||
{{ default (include "fluent-bit.name" .) .Values.fluentBit.serviceAccount.name }}
|
||||
{{- else -}}
|
||||
{{ default "default" .Values.fluentBit.serviceAccount.name }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Fluent-bit image with tag/digest
|
||||
*/}}
|
||||
{{- define "fluent-bit.image" -}}
|
||||
{{ default .Values.global.image.repository .Values.fluentBit.image.repository }}/{{ .Values.fluentBit.image.name }}:{{ .Values.fluentBit.image.buildTag | default .Chart.AppVersion }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "logrotate.serviceAccountName" -}}
|
||||
{{- if .Values.fluentBit.logrotate.serviceAccount.enabled -}}
|
||||
{{ default "logrotate" .Values.fluentBit.logrotate.serviceAccount.name }}
|
||||
{{- else -}}
|
||||
{{ default "default" .Values.fluentBit.logrotate.serviceAccount.name }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Value of efs_root based on the dataplane type
|
||||
*/}}
|
||||
{{- define "efs_root.value" -}}
|
||||
{{- $dataplaneMode := include "parent.dataplaneMode" . -}}
|
||||
{{- $clusterRefId := tpl .Values.common.clusterRefId . -}}
|
||||
{{- if eq $dataplaneMode "shared" -}}/efs{{- else -}}/efs/clusters/{{ $clusterRefId }}{{- end -}}
|
||||
{{- end -}}
|
||||
39
templates/fluent-bit/calico.netpol.yaml
Normal file
39
templates/fluent-bit/calico.netpol.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
{{- if .Values.fluentBit.calicoNetpol.enabled }}
|
||||
apiVersion: projectcalico.org/v3
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: {{ template "fluent-bit.appName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
order: 10
|
||||
selector: dplane == 'fluent-bit'
|
||||
types:
|
||||
- Egress
|
||||
egress:
|
||||
# allow to communicate to DNS pods
|
||||
- action: Allow
|
||||
protocol: UDP
|
||||
destination:
|
||||
namespaceSelector: projectcalico.org/name == 'kube-system'
|
||||
ports:
|
||||
- 53
|
||||
- action: Allow
|
||||
protocol: TCP
|
||||
destination:
|
||||
namespaceSelector: projectcalico.org/name == 'kube-system'
|
||||
ports:
|
||||
- 53
|
||||
# allow to communicate with itself for clustering
|
||||
- action: Allow
|
||||
destination:
|
||||
selector: dplane == 'fluent-bit'
|
||||
namespaceSelector: projectcalico.org/name == '{{ .Release.Namespace }}'
|
||||
protocol: TCP
|
||||
# allow to communicate with k8s api server
|
||||
- action: Allow
|
||||
destination:
|
||||
services:
|
||||
name: kubernetes
|
||||
namespace: default
|
||||
protocol: TCP
|
||||
{{- end}}
|
||||
104
templates/fluent-bit/configmap-luascript.yaml
Normal file
104
templates/fluent-bit/configmap-luascript.yaml
Normal file
@@ -0,0 +1,104 @@
|
||||
{{- if and .Values.fluentBit.enabled (eq .Values.fluentBit.kind "DaemonSet") -}}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "fluent-bit.appName" . }}-luascript
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluent-bit.labels" . | nindent 4 }}
|
||||
data:
|
||||
create_runtime_Directories.lua: |
|
||||
local function resolve_folder_path(folder_path, file_name)
|
||||
if file_name == "inbound" then
|
||||
folder_path = folder_path .. "/" .. file_name
|
||||
end
|
||||
return folder_path
|
||||
end
|
||||
|
||||
local function write_log(folder_path, file_name, log_content)
|
||||
local file_path = folder_path .. "/" .. file_name .. ".log"
|
||||
local file, err = io.open(file_path, "a")
|
||||
if file then
|
||||
-- Write log content to the file
|
||||
file:write(log_content .. "\n")
|
||||
file:close()
|
||||
print(string.format("Successfully wrote log to file: %s", file_path))
|
||||
else
|
||||
print(string.format("Failed to open file: %s, error: %s", file_path, err))
|
||||
end
|
||||
end
|
||||
|
||||
local function handle_txn_logs(tag, timestamp, record, file_name)
|
||||
local orgId = record["orgSchema"]
|
||||
local modeId = record["modeId"]
|
||||
local transactionId = record["transactionId"]
|
||||
local log_content = record["log"]
|
||||
|
||||
if not orgId or not modeId then
|
||||
print("Skipping directory creation: orgId or modeId is nil")
|
||||
return 1, timestamp, record
|
||||
end
|
||||
|
||||
local efs_root = os.getenv("efs_root")
|
||||
print(string.format("efs root value...: %s", efs_root))
|
||||
local folder_path = string.format("%s/logs/%s/%s/transaction/%s", efs_root, orgId, modeId, transactionId)
|
||||
folder_path = resolve_folder_path(folder_path, file_name)
|
||||
|
||||
local success, exit_type, exit_code = os.execute("mkdir -p " .. folder_path)
|
||||
|
||||
if success then
|
||||
write_log(folder_path, file_name, log_content)
|
||||
else
|
||||
print(string.format("Failed to create folder: %s", folder_path))
|
||||
end
|
||||
return 1, timestamp, record
|
||||
end
|
||||
|
||||
local function handle_app_logs(tag, timestamp, record, dir_name, file_name)
|
||||
local log_content = record["log"]
|
||||
local pod_name = record["kubernetes"]["pod_name"]
|
||||
print(string.format("pod name...: %s", pod_name))
|
||||
|
||||
local efs_root = os.getenv("efs_root")
|
||||
print(string.format("efs root value...: %s", efs_root))
|
||||
local folder_path = string.format("%s/logs/%s/%s", efs_root, dir_name, pod_name)
|
||||
folder_path = resolve_folder_path(folder_path, file_name)
|
||||
|
||||
write_log(folder_path, file_name, log_content)
|
||||
|
||||
return 1, timestamp, record
|
||||
end
|
||||
|
||||
function handle_orchestrator_txn_logs(tag, timestamp, record)
|
||||
return handle_txn_logs(tag, timestamp, record, "ir")
|
||||
end
|
||||
|
||||
function handle_inbound_txn_logs(tag, timestamp, record)
|
||||
return handle_txn_logs(tag, timestamp, record, "inbound")
|
||||
end
|
||||
|
||||
function handle_fusion_operator_logs(tag, timestamp, record)
|
||||
return handle_app_logs(tag, timestamp, record, "fusion-operator", "fusion-operator")
|
||||
end
|
||||
|
||||
function handle_envoy_logs(tag, timestamp, record)
|
||||
return handle_app_logs(tag, timestamp, record, "envoy", "envoy")
|
||||
end
|
||||
|
||||
function handle_orchestrator_logs(tag, timestamp, record)
|
||||
return handle_app_logs(tag, timestamp, record, "ir", "orchestrator")
|
||||
end
|
||||
|
||||
function handle_inbound_logs(tag, timestamp, record)
|
||||
return handle_app_logs(tag, timestamp, record, "inbound", "inbound")
|
||||
end
|
||||
|
||||
function handle_pep_server_logs(tag, timestamp, record)
|
||||
return handle_app_logs(tag, timestamp, record, "pep-server", "pep-server")
|
||||
end
|
||||
|
||||
function handle_sink_agent_logs(tag, timestamp, record)
|
||||
return handle_app_logs(tag, timestamp, record, "sinkagent", "sinkagent")
|
||||
end
|
||||
|
||||
{{- end }}
|
||||
242
templates/fluent-bit/configmap_daemonset.yaml
Normal file
242
templates/fluent-bit/configmap_daemonset.yaml
Normal file
@@ -0,0 +1,242 @@
|
||||
{{- if and .Values.fluentBit.enabled (eq .Values.fluentBit.kind "DaemonSet") -}}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "fluent-bit.appName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluent-bit.labels" . | nindent 4 }}
|
||||
data:
|
||||
custom_parsers.conf: |
|
||||
[PARSER]
|
||||
Name docker_no_time
|
||||
Format json
|
||||
Time_Keep Off
|
||||
Time_Key time
|
||||
Time_Format %Y-%m-%dT%H:%M:%S.%L
|
||||
[PARSER]
|
||||
Name parser
|
||||
Format regex
|
||||
Regex ^(?<orgSchema>[^\s]+) (?<modeId>[0-9a-fA-F-]{36}) (?<transactionId>[0-9a-fA-F-]{36}) (?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}:\d{3}) \[(?<thread>[^\]]+)\] (?<level>\w+) +(?<class>[^\s]+) \((?<traceId>[^,]*),(?<spanId>[^\)]*)\) - (?<message>.*)$
|
||||
fluent-bit.conf: |
|
||||
[SERVICE]
|
||||
Daemon Off
|
||||
Flush 1
|
||||
Log_Level info
|
||||
storage.path /var/log/fluent-bit/storage
|
||||
storage.backlog.flush_on_shutdown On
|
||||
Parsers_File /fluent-bit/etc/parsers.conf
|
||||
Parsers_File /fluent-bit/etc/conf/custom_parsers.conf
|
||||
HTTP_Server On
|
||||
HTTP_Listen 0.0.0.0
|
||||
HTTP_Port 2020
|
||||
Health_Check On
|
||||
|
||||
{{- with .Values.fluentBit.config.service }}
|
||||
{{ tpl . $ | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
[INPUT]
|
||||
Name tail
|
||||
Path /var/log/containers/*orchestrator*.log
|
||||
multiline.parser docker, cri
|
||||
DB /var/log/fluent-bit/storage/orchestrator-txn-tail.db
|
||||
storage.type filesystem
|
||||
read_from_head true
|
||||
Tag orchestrator.txn.*
|
||||
Skip_Long_Lines On
|
||||
|
||||
[INPUT]
|
||||
Name tail
|
||||
Path /var/log/containers/*orchestrator*.log
|
||||
multiline.parser docker, cri
|
||||
DB /var/log/fluent-bit/storage/orchestrator-tail.db
|
||||
storage.type filesystem
|
||||
read_from_head true
|
||||
Tag orchestrator.app.log*
|
||||
Skip_Long_Lines On
|
||||
|
||||
[INPUT]
|
||||
Name tail
|
||||
Path /var/log/containers/*sink-agent*.log
|
||||
multiline.parser docker, cri
|
||||
DB /var/log/fluent-bit/storage/sink-agent-tail.db
|
||||
storage.type filesystem
|
||||
read_from_head true
|
||||
Tag sink-agent.*
|
||||
Skip_Long_Lines On
|
||||
|
||||
[INPUT]
|
||||
Name tail
|
||||
Path /var/log/containers/*pep-server*.log
|
||||
multiline.parser docker, cri
|
||||
DB /var/log/fluent-bit/storage/pep-server-tail.db
|
||||
storage.type filesystem
|
||||
read_from_head true
|
||||
Tag pep_server.*
|
||||
Skip_Long_Lines On
|
||||
|
||||
[INPUT]
|
||||
Name tail
|
||||
Path /var/log/containers/*fusion-operator*.log
|
||||
multiline.parser docker, cri
|
||||
DB /var/log/fluent-bit/storage/fusion-operator-tail.db
|
||||
storage.type filesystem
|
||||
read_from_head true
|
||||
Tag fusion_operator.*
|
||||
Skip_Long_Lines On
|
||||
|
||||
[INPUT]
|
||||
Name tail
|
||||
Path /var/log/containers/*envoy*.log
|
||||
multiline.parser docker, cri
|
||||
DB /var/log/fluent-bit/storage/envoy-tail.db
|
||||
storage.type filesystem
|
||||
read_from_head true
|
||||
Tag envoy.*
|
||||
Skip_Long_Lines On
|
||||
|
||||
[INPUT]
|
||||
Name tail
|
||||
Path /var/log/containers/*inbound*.log
|
||||
multiline.parser docker, cri
|
||||
DB /var/log/fluent-bit/storage/inbound-worker-txn-tail.db
|
||||
storage.type filesystem
|
||||
read_from_head true
|
||||
Tag inbound.txn.*
|
||||
Skip_Long_Lines On
|
||||
|
||||
[INPUT]
|
||||
Name tail
|
||||
Path /var/log/containers/*inbound*.log
|
||||
multiline.parser docker, cri
|
||||
DB /var/log/fluent-bit/storage/inbound-worker-tail.db
|
||||
storage.type filesystem
|
||||
read_from_head true
|
||||
Tag inbound.app.log*
|
||||
Skip_Long_Lines On
|
||||
|
||||
{{- with .Values.fluentBit.config.inputs }}
|
||||
{{ tpl . $ | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
[FILTER]
|
||||
Name kubernetes
|
||||
Match orchestrator.txn.*
|
||||
Kube_Tag_Prefix orchestrator.txn.var.log.containers.
|
||||
Merge_Log On
|
||||
|
||||
[FILTER]
|
||||
Name parser
|
||||
Match orchestrator.txn.*
|
||||
Key_Name log
|
||||
Parser parser
|
||||
Reserve_Data On
|
||||
Preserve_Key On
|
||||
|
||||
[FILTER]
|
||||
Name lua
|
||||
Match orchestrator.txn.*
|
||||
Script /fluent-bit/etc/lua/create_runtime_Directories.lua
|
||||
Call handle_orchestrator_txn_logs
|
||||
|
||||
[FILTER]
|
||||
Name kubernetes
|
||||
Match orchestrator.app.log*
|
||||
Kube_Tag_Prefix orchestrator.app.log.var.log.containers.
|
||||
Merge_Log On
|
||||
|
||||
[FILTER]
|
||||
Name lua
|
||||
Match orchestrator.app.log*
|
||||
Script /fluent-bit/etc/lua/create_runtime_Directories.lua
|
||||
Call handle_orchestrator_logs
|
||||
|
||||
[FILTER]
|
||||
Name kubernetes
|
||||
Match sink-agent.*
|
||||
Kube_Tag_Prefix sink-agent.var.log.containers.
|
||||
Merge_Log On
|
||||
|
||||
[FILTER]
|
||||
Name lua
|
||||
Match sink-agent.*
|
||||
Script /fluent-bit/etc/lua/create_runtime_Directories.lua
|
||||
Call handle_sink_agent_logs
|
||||
|
||||
[FILTER]
|
||||
Name kubernetes
|
||||
Match pep_server.*
|
||||
Kube_Tag_Prefix pep-server.var.log.containers.
|
||||
Merge_Log On
|
||||
|
||||
[FILTER]
|
||||
Name lua
|
||||
Match pep_server.*
|
||||
Script /fluent-bit/etc/lua/create_runtime_Directories.lua
|
||||
Call handle_pep_server_logs
|
||||
|
||||
[FILTER]
|
||||
Name kubernetes
|
||||
Match fusion_operator.*
|
||||
Kube_Tag_Prefix fusion-operator.var.log.containers.
|
||||
Merge_Log On
|
||||
|
||||
[FILTER]
|
||||
Name lua
|
||||
Match fusion_operator.*
|
||||
Script /fluent-bit/etc/lua/create_runtime_Directories.lua
|
||||
Call handle_fusion_operator_logs
|
||||
|
||||
[FILTER]
|
||||
Name kubernetes
|
||||
Match envoy.*
|
||||
Kube_Tag_Prefix envoy.var.log.containers.
|
||||
Merge_Log On
|
||||
|
||||
[FILTER]
|
||||
Name lua
|
||||
Match envoy.*
|
||||
Script /fluent-bit/etc/lua/create_runtime_Directories.lua
|
||||
Call handle_envoy_logs
|
||||
|
||||
[FILTER]
|
||||
Name kubernetes
|
||||
Match inbound.txn.*
|
||||
Kube_Tag_Prefix inbound.txn.var.log.containers.
|
||||
Merge_Log On
|
||||
|
||||
[FILTER]
|
||||
Name parser
|
||||
Match inbound.txn.*
|
||||
Key_Name log
|
||||
Parser parser
|
||||
Reserve_Data On
|
||||
Preserve_Key On
|
||||
|
||||
[FILTER]
|
||||
Name lua
|
||||
Match inbound.txn.*
|
||||
Script /fluent-bit/etc/lua/create_runtime_Directories.lua
|
||||
Call handle_inbound_txn_logs
|
||||
|
||||
[FILTER]
|
||||
Name kubernetes
|
||||
Match inbound.app.log*
|
||||
Kube_Tag_Prefix inbound.app.log.var.log.containers.
|
||||
Merge_Log On
|
||||
|
||||
[FILTER]
|
||||
Name lua
|
||||
Match inbound.app.log*
|
||||
Script /fluent-bit/etc/lua/create_runtime_Directories.lua
|
||||
Call handle_inbound_logs
|
||||
|
||||
{{- with .Values.fluentBit.config.filters }}
|
||||
{{ tpl . $ | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
{{- with .Values.fluentBit.config.outputs }}
|
||||
{{ tpl . $ | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
63
templates/fluent-bit/configmap_deployment.yaml
Normal file
63
templates/fluent-bit/configmap_deployment.yaml
Normal file
@@ -0,0 +1,63 @@
|
||||
{{- if and .Values.fluentBit.enabled (eq .Values.fluentBit.kind "Deployment") -}}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "fluent-bit.appName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluent-bit.labels" . | nindent 4 }}
|
||||
data:
|
||||
fluent-bit.conf: |
|
||||
[SERVICE]
|
||||
Daemon Off
|
||||
Flush 1
|
||||
Log_Level info
|
||||
storage.path {{ include "efs_root.value" . -}}/fluent-bit/storage
|
||||
storage.backlog.flush_on_shutdown On
|
||||
Parsers_File /fluent-bit/etc/parsers.conf
|
||||
HTTP_Server On
|
||||
HTTP_Listen 0.0.0.0
|
||||
HTTP_Port 2020
|
||||
Health_Check On
|
||||
|
||||
{{- with .Values.fluentBit.config.service }}
|
||||
{{ tpl . $ | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
{{- $inputs := list
|
||||
(dict "name" "inbound" "path" "inbound/*/inbound/inbound.log" "tag" "inbound.app.log*")
|
||||
(dict "name" "ir" "path" "ir/*/orchestrator.log" "tag" "orchestrator.app.log*")
|
||||
(dict "name" "pep-server" "path" "pep-server/*/pep-server.log" "tag" "pep-server.app.log*")
|
||||
(dict "name" "sinkagent" "path" "sinkagent/*/sinkagent.log" "tag" "sinkagent.app.log*")
|
||||
-}}
|
||||
{{- if eq (include "parent.dataplaneMode" . ) "shared" }}
|
||||
{{- $inputs = append $inputs (dict "name" "fusion-operator" "path" "fusion-operator/*/fusion-operator*.log" "tag" "fusion-operator.app.log*") }}
|
||||
{{- end}}
|
||||
{{- $efsRoot := include "efs_root.value" . }}
|
||||
{{- range $inputs }}
|
||||
[INPUT]
|
||||
Name tail
|
||||
Path {{ $efsRoot }}/logs/{{ .path }}
|
||||
multiline.parser docker, cri
|
||||
DB {{ $efsRoot }}/fluent-bit/storage/{{ .name }}-tail.db
|
||||
DB.locking true
|
||||
Ignore_Older 1d
|
||||
storage.type filesystem
|
||||
read_from_head true
|
||||
Tag {{ .tag }}
|
||||
Skip_Long_Lines On
|
||||
{{- end }}
|
||||
|
||||
|
||||
{{- with .Values.fluentBit.config.inputs }}
|
||||
{{ tpl . $ | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
{{- with .Values.fluentBit.config.filters }}
|
||||
{{ tpl . $ | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
{{- with .Values.fluentBit.config.outputs }}
|
||||
{{ tpl . $ | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
175
templates/fluent-bit/fluentbit.yaml
Normal file
175
templates/fluent-bit/fluentbit.yaml
Normal file
@@ -0,0 +1,175 @@
|
||||
{{- if .Values.fluentBit.enabled -}}
|
||||
apiVersion: apps/v1
|
||||
kind: {{ .Values.fluentBit.kind }}
|
||||
metadata:
|
||||
name: {{ template "fluent-bit.appName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluent-bit.labels" . | nindent 4 }}
|
||||
{{- with .Values.fluentBit.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.fluentBit.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "fluent-bit.selectorLabels" . | nindent 6 }}
|
||||
{{- if eq .Values.fluentBit.kind "Deployment" }}
|
||||
strategy:
|
||||
type: Recreate
|
||||
{{- else if eq .Values.fluentBit.kind "DaemonSet" }}
|
||||
{{- with .Values.fluentBit.updateStrategy }}
|
||||
updateStrategy:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.fluentBit.minReadySeconds }}
|
||||
minReadySeconds: {{ . }}
|
||||
{{- end }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "fluent-bit.selectorLabels" . | nindent 8 }}
|
||||
{{- with .Values.fluentBit.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
annotations:
|
||||
checksum/config: {{ include (print $.Template.BasePath "/fluent-bit/configmap_" ( lower .Values.fluentBit.kind ) ".yaml") . | sha256sum }}
|
||||
{{- if eq .Values.fluentBit.kind "DaemonSet" }}
|
||||
checksum/luascripts: {{ include (print $.Template.BasePath "/fluent-bit/configmap-luascript.yaml") . | sha256sum }}
|
||||
{{- end }}
|
||||
{{- with .Values.fluentBit.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
serviceAccountName: {{ include "fluent-bit.serviceAccountName" . }}
|
||||
{{- with .Values.global.image.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- if .Values.fluentBit.podSecurityContextEnabled -}}
|
||||
{{- with .Values.fluentBit.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.fluentBit.terminationGracePeriodSeconds }}
|
||||
terminationGracePeriodSeconds: {{ . }}
|
||||
{{- end }}
|
||||
hostNetwork: {{ .Values.fluentBit.hostNetwork }}
|
||||
dnsPolicy: {{ .Values.fluentBit.dnsPolicy }}
|
||||
restartPolicy: {{ .Values.fluentBit.restartPolicy }}
|
||||
schedulerName: {{ .Values.fluentBit.schedulerName }}
|
||||
{{- with .Values.fluentBit.initContainers }}
|
||||
initContainers:
|
||||
{{- if kindIs "string" . }}
|
||||
{{- tpl . $ | nindent 6 }}
|
||||
{{- else }}
|
||||
{{- toYaml . | nindent 6 }}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: {{ include "fluent-bit.appName" . }}
|
||||
{{- with .Values.fluentBit.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
image: {{ include "fluent-bit.image" . }}
|
||||
imagePullPolicy: {{ .Values.global.image.pullPolicy }}
|
||||
{{- if or .Values.fluentBit.env .Values.fluentBit.envWithTpl }}
|
||||
env:
|
||||
{{- with .Values.fluentBit.env }}
|
||||
{{- toYaml . | nindent 10 }}
|
||||
{{- end }}
|
||||
{{- range $item := .Values.fluentBit.envWithTpl }}
|
||||
- name: {{ $item.name }}
|
||||
value: {{ tpl $item.value $ | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: configmap-common
|
||||
{{- if .Values.fluentBit.envFrom }}
|
||||
{{- toYaml .Values.fluentBit.envFrom | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.fluentBit.command }}
|
||||
command:
|
||||
{{- toYaml . | nindent 10 }}
|
||||
{{- end }}
|
||||
{{- if .Values.fluentBit.args }}
|
||||
args:
|
||||
{{- toYaml .Values.fluentBit.args | nindent 10 }}
|
||||
{{- end}}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.fluentBit.metricsPort }}
|
||||
protocol: TCP
|
||||
{{- if .Values.fluentBit.extraPorts }}
|
||||
{{- range .Values.fluentBit.extraPorts }}
|
||||
- name: {{ .name }}
|
||||
containerPort: {{ .containerPort }}
|
||||
protocol: {{ .protocol }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
livenessProbe: {{- toYaml .Values.fluentBit.livenessProbe | nindent 12 }}
|
||||
startupProbe: {{- toYaml .Values.fluentBit.startupProbe | nindent 12 }}
|
||||
readinessProbe: {{- toYaml .Values.fluentBit.readinessProbe | nindent 12 }}
|
||||
{{- with .Values.fluentBit.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /fluent-bit/etc/conf
|
||||
- mountPath: /efs
|
||||
name: {{ .Values.global.volumeStorageName }}
|
||||
{{- if eq .Values.fluentBit.kind "DaemonSet" }}
|
||||
- mountPath: /fluent-bit/etc/lua
|
||||
name: lua-scripts
|
||||
{{- toYaml .Values.fluentBit.daemonSetVolumeMounts | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.fluentBit.extraVolumeMounts }}
|
||||
{{- toYaml .Values.fluentBit.extraVolumeMounts | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.fluentBit.extraContainers }}
|
||||
{{- if kindIs "string" .Values.fluentBit.extraContainers }}
|
||||
{{- tpl .Values.fluentBit.extraContainers $ | nindent 2 }}
|
||||
{{- else }}
|
||||
{{- toYaml .Values.fluentBit.extraContainers | nindent 2 }}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
{{- if eq .Values.fluentBit.kind "Deployment" }}
|
||||
{{- with .Values.fluentBit.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.fluentBit.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.fluentBit.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: {{ .Values.global.volumeStorageName }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Release.Namespace }}-{{ .Values.global.claimName }}
|
||||
- name: config
|
||||
configMap:
|
||||
name: {{ default (include "fluent-bit.appName" .) .Values.fluentBit.existingConfigMap }}
|
||||
{{- if eq .Values.fluentBit.kind "DaemonSet" }}
|
||||
- name: lua-scripts
|
||||
configMap:
|
||||
defaultMode: 420
|
||||
name: {{ default (include "fluent-bit.appName" .) .Values.fluentBit.existingConfigMap }}-luascript
|
||||
{{- toYaml .Values.fluentBit.daemonSetVolumes | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.fluentBit.extraVolumes }}
|
||||
{{- toYaml .Values.fluentBit.extraVolumes | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
33
templates/fluent-bit/hpa.yaml
Normal file
33
templates/fluent-bit/hpa.yaml
Normal file
@@ -0,0 +1,33 @@
|
||||
{{- if and .Values.fluentBit.autoscaling.enabled (eq .Values.fluentBit.kind "Deployment") }}
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ template "fluent-bit.appName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "fluent-bit.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ template "fluent-bit.appName" . }}
|
||||
minReplicas: {{ .Values.fluentBit.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.fluentBit.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.fluentBit.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.fluentBit.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.fluentBit.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.fluentBit.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
33
templates/fluent-bit/logrotate/calico.netpol.yaml
Normal file
33
templates/fluent-bit/logrotate/calico.netpol.yaml
Normal file
@@ -0,0 +1,33 @@
|
||||
{{- if .Values.fluentBit.logrotate.calicoNetpol.enabled }}
|
||||
apiVersion: projectcalico.org/v3
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: logrotate-network-policy
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
order: 10
|
||||
selector: dplane == 'logrotate-job'
|
||||
types:
|
||||
- Egress
|
||||
egress:
|
||||
# allow to communicate to DNS pods
|
||||
- action: Allow
|
||||
protocol: UDP
|
||||
destination:
|
||||
namespaceSelector: projectcalico.org/name == 'kube-system'
|
||||
ports:
|
||||
- 53
|
||||
- action: Allow
|
||||
protocol: TCP
|
||||
destination:
|
||||
namespaceSelector: projectcalico.org/name == 'kube-system'
|
||||
ports:
|
||||
- 53
|
||||
# allow to communicate with k8s api server
|
||||
- action: Allow
|
||||
destination:
|
||||
services:
|
||||
name: kubernetes
|
||||
namespace: default
|
||||
protocol: TCP
|
||||
{{- end}}
|
||||
76
templates/fluent-bit/logrotate/logrotate-configmap.yaml
Normal file
76
templates/fluent-bit/logrotate/logrotate-configmap.yaml
Normal file
@@ -0,0 +1,76 @@
|
||||
{{- if and .Values.fluentBit.enabled .Values.fluentBit.logrotate.enabled -}}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: logrotate-{{ template "fluent-bit.appName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "dataplane.labels" . | nindent 4 }}
|
||||
data:
|
||||
dynamic-logrotate.sh: |
|
||||
#!/bin/sh
|
||||
set -e
|
||||
STATE_FILE="/tmp/logrotate.status"
|
||||
LOGROTATE_CONFIG="/tmp/dynamic-logrotate.conf"
|
||||
|
||||
# Determine base path based on dataplane mode
|
||||
BASE_PATH="{{- if eq (include "parent.dataplaneMode" .) "shared" -}}/efs/logs{{- else -}}/efs/clusters/{{ tpl .Values.common.clusterRefId . }}/logs{{- end }}"
|
||||
|
||||
# List of service folders to scan
|
||||
SERVICES="sink-agent inbound-worker pep-server orchestrator envoy fusion-operator"
|
||||
|
||||
# Clean up the old config file
|
||||
echo "" > "$LOGROTATE_CONFIG"
|
||||
|
||||
# Get running pod names in current namespace
|
||||
POD_NAMES=$(kubectl get pods -n $(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) \
|
||||
--field-selector=status.phase=Running \
|
||||
-o jsonpath='{.items[*].metadata.name}')
|
||||
|
||||
for svc in $SERVICES; do
|
||||
for pod in $POD_NAMES; do
|
||||
case "$svc" in
|
||||
"envoy")
|
||||
[[ "$pod" != *envoy* ]] && continue
|
||||
LOG_PATH="$BASE_PATH/envoy/$pod/envoy.log"
|
||||
;;
|
||||
"fusion-operator")
|
||||
[[ "$pod" != *fusion-operator* ]] && continue
|
||||
LOG_PATH="$BASE_PATH/fusion-operator/$pod/fusion-operator.log"
|
||||
;;
|
||||
"sink-agent")
|
||||
[[ "$pod" != *sink-agent* ]] && continue
|
||||
LOG_PATH="$BASE_PATH/sinkagent/$pod/sinkagent.log"
|
||||
;;
|
||||
"inbound-worker")
|
||||
[[ "$pod" != *inbound-worker* ]] && continue
|
||||
LOG_PATH="$BASE_PATH/inbound/$pod/inbound/inbound.log"
|
||||
;;
|
||||
"pep-server")
|
||||
[[ "$pod" != *pep-server* ]] && continue
|
||||
LOG_PATH="$BASE_PATH/pep-server/$pod/pep-server.log"
|
||||
;;
|
||||
"orchestrator")
|
||||
[[ "$pod" != *orchestrator* ]] && continue
|
||||
LOG_PATH="$BASE_PATH/ir/$pod/orchestrator.log"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -f "$LOG_PATH" ]; then
|
||||
echo "$LOG_PATH {
|
||||
size 10M
|
||||
rotate -1
|
||||
missingok
|
||||
dateext
|
||||
dateformat .%Y-%m-%d-%H-%M
|
||||
notifempty
|
||||
create
|
||||
nocompress
|
||||
}" >> "$LOGROTATE_CONFIG"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# Run logrotate with the generated config
|
||||
/usr/sbin/logrotate -v --state "$STATE_FILE" "$LOGROTATE_CONFIG"
|
||||
{{- end }}
|
||||
64
templates/fluent-bit/logrotate/logrotate-cronjob.yaml
Normal file
64
templates/fluent-bit/logrotate/logrotate-cronjob.yaml
Normal file
@@ -0,0 +1,64 @@
|
||||
{{- if and .Values.fluentBit.enabled .Values.fluentBit.logrotate.enabled -}}
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: logrotate-{{ template "fluent-bit.appName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
dplane: "logrotate-job"
|
||||
spec:
|
||||
concurrencyPolicy: Forbid
|
||||
failedJobsHistoryLimit: 1
|
||||
jobTemplate:
|
||||
spec:
|
||||
ttlSecondsAfterFinished: {{ .Values.fluentBit.logrotate.job_ttl }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
dplane: "logrotate-job"
|
||||
spec:
|
||||
serviceAccountName: {{ include "logrotate.serviceAccountName" . }}
|
||||
containers:
|
||||
- image: "{{ default .Values.global.image.repository .Values.global.alpinetools.image.repository }}/{{ .Values.global.alpinetools.image.name }}:{{ .Values.global.alpinetools.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.global.image.pullPolicy }}
|
||||
command: [ "/bin/sh", "-c" ]
|
||||
args:
|
||||
- |
|
||||
sh /etc/logrotate.d/dynamic-logrotate.sh
|
||||
name: logrotate
|
||||
{{- with .Values.fluentBit.logrotate.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 16 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- mountPath: /etc/logrotate.d
|
||||
name: logrotate-config
|
||||
- mountPath: /efs
|
||||
name: {{ .Values.global.volumeStorageName }}
|
||||
- mountPath: /tmp
|
||||
name: tmpdir
|
||||
restartPolicy: OnFailure
|
||||
{{- with .Values.global.image.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 10 }}
|
||||
{{- end }}
|
||||
{{- if .Values.fluentBit.logrotate.podSecurityContextEnabled -}}
|
||||
{{- with .Values.fluentBit.logrotate.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- configMap:
|
||||
defaultMode: 420
|
||||
name: logrotate-{{ template "fluent-bit.appName" . }}
|
||||
name: logrotate-config
|
||||
- name: {{ .Values.global.volumeStorageName }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Release.Namespace }}-{{ .Values.global.claimName }}
|
||||
- emptyDir: {}
|
||||
name: tmpdir
|
||||
schedule: "{{ .Values.fluentBit.logrotate.schedule }}"
|
||||
successfulJobsHistoryLimit: 1
|
||||
suspend: false
|
||||
{{- end }}
|
||||
17
templates/fluent-bit/logrotate/role.yaml
Normal file
17
templates/fluent-bit/logrotate/role.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
{{- if ( and .Values.fluentBit.logrotate.serviceAccount.enabled ( not .Values.fluentBit.logrotate.serviceAccount.preexisting ) ) -}}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: logrotate-{{ template "fluent-bit.appName" . }}-role
|
||||
labels:
|
||||
{{- include "dataplane.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- namespaces
|
||||
- pods
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
{{- end }}
|
||||
16
templates/fluent-bit/logrotate/roleBinding.yaml
Normal file
16
templates/fluent-bit/logrotate/roleBinding.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
{{- if ( and .Values.fluentBit.logrotate.serviceAccount.enabled ( not .Values.fluentBit.logrotate.serviceAccount.preexisting ) ) -}}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: logrotate-{{ template "fluent-bit.appName" . }}-role-binding
|
||||
labels:
|
||||
{{- include "dataplane.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: logrotate-{{ template "fluent-bit.appName" . }}-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "logrotate.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
12
templates/fluent-bit/logrotate/serviceaccount.yaml
Normal file
12
templates/fluent-bit/logrotate/serviceaccount.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
{{- if .Values.fluentBit.logrotate.serviceAccount.enabled -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "logrotate.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "dataplane.labels" . | nindent 4 }}
|
||||
{{- with .Values.fluentBit.logrotate.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
12
templates/fluent-bit/poddisruptionbudget.yaml
Normal file
12
templates/fluent-bit/poddisruptionbudget.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
{{- if and .Values.fluentBit.podDisruptionBudget.enabled (eq .Values.fluentBit.kind "Deployment") }}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ template "fluent-bit.appName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
minAvailable: {{ .Values.fluentBit.podDisruptionBudget.minPods }}
|
||||
selector:
|
||||
matchLabels:
|
||||
dplane: {{ .Chart.Name }}
|
||||
{{- end}}
|
||||
18
templates/fluent-bit/role.yaml
Normal file
18
templates/fluent-bit/role.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
{{- if ( and .Values.fluentBit.serviceAccount.enabled ( not .Values.fluentBit.serviceAccount.preexisting ) ) -}}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ include "fluent-bit.appName" . }}-role
|
||||
labels:
|
||||
{{- include "fluent-bit.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- namespaces
|
||||
- pods
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
{{- end }}
|
||||
16
templates/fluent-bit/roleBinding.yaml
Normal file
16
templates/fluent-bit/roleBinding.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
{{- if ( and .Values.fluentBit.serviceAccount.enabled ( not .Values.fluentBit.serviceAccount.preexisting ) ) -}}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ include "fluent-bit.appName" . }}-role-binding
|
||||
labels:
|
||||
{{- include "fluent-bit.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: {{ include "fluent-bit.appName" . }}-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "fluent-bit.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
12
templates/fluent-bit/serviceaccount.yaml
Normal file
12
templates/fluent-bit/serviceaccount.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
{{- if .Values.fluentBit.serviceAccount.enabled -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "fluent-bit.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "fluent-bit.labels" . | nindent 4 }}
|
||||
{{- with .Values.fluentBit.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
Reference in New Issue
Block a user