# _helpers.tpl
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "metallb.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "metallb.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "metallb.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Create the name of the controller service account to use
*/}}
{{- define "metallb.controllerServiceAccountName" -}}
{{- if .Values.serviceAccounts.controller.create -}}
    {{ default (printf "%s-controller" (include "metallb.fullname" .)) .Values.serviceAccounts.controller.name }}
{{- else -}}
    {{ default "default" .Values.serviceAccounts.controller.name }}
{{- end -}}
{{- end -}}

{{/*
Create the name of the speaker service account to use
*/}}
{{- define "metallb.speakerServiceAccountName" -}}
{{- if .Values.serviceAccounts.speaker.create -}}
    {{ default (printf "%s-speaker" (include "metallb.fullname" .)) .Values.serviceAccounts.speaker.name }}
{{- else -}}
    {{ default "default" .Values.serviceAccounts.speaker.name }}
{{- end -}}
{{- end -}}

{{/*
Create the name of the settings ConfigMap to use.
*/}}
{{- define "metallb.configMapName" -}}
{{- if .Values.configInline -}}
    {{ include "metallb.fullname" . }}
{{- else -}}
    {{ .Values.existingConfigMap }}
{{- end -}}
{{- end -}}
 # config.yaml
{{- if .Values.configInline }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ template "metallb.fullname" . }}
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
data:
  config: |
{{ toYaml .Values.configInline | indent 4 }}
{{- end }}
 # controller.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ template "metallb.fullname" . }}-controller
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
    component: controller
spec:
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: {{ template "metallb.name" . }}
      component: controller
      release: {{ .Release.Name | quote }}
  template:
    metadata:
      labels:
        heritage: {{ .Release.Service | quote }}
        release: {{ .Release.Name | quote }}
        chart: {{ template "metallb.chart" . }}
        app: {{ template "metallb.name" . }}
        component: controller
{{- if .Values.prometheus.scrapeAnnotations }}
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "7472"
{{- end }}
    spec:
      serviceAccountName: {{ template "metallb.controllerServiceAccountName" . }}
      terminationGracePeriodSeconds: 0
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534 # nobody
      nodeSelector:
        "beta.kubernetes.io/os": linux
        {{- with .Values.controller.nodeSelector }}
{{ toYaml . | indent 8 }}
    {{- end }}
    {{- with .Values.controller.tolerations }}
      tolerations:
{{ toYaml . | indent 8 }}
    {{- end }}
    {{- with .Values.controller.affinity }}
      affinity:
{{ toYaml . | indent 8 }}
    {{- end }}
      containers:
      - name: controller
        image: {{ .Values.controller.image.repository }}:{{ .Values.controller.image.tag }}
        imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
        args:
        - --port=7472
        - --config={{ template "metallb.configMapName" . }}
        ports:
        - name: monitoring
          containerPort: 7472
        resources:
{{ toYaml .Values.controller.resources | indent 10 }}
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - all
          readOnlyRootFilesystem: true
 # prometheusrules.yaml
{{- if .Values.prometheus.prometheusRule.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: {{ template "metallb.fullname" . }}
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
spec:
  groups:
  - name: {{ template "metallb.fullname" . }}.rules
    rules:
    - alert: MetalLBStaleConfig
      annotations:
        message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container_name }} on {{ $labels.instance
          }} has a stale config for > 1 minute'`}}
      expr: metallb_k8s_client_config_stale_bool{job="{{ .Values.prometheus.serviceMonitor.jobLabel }}"} == 1
      for: 1m
      labels:
        severity: warning
    - alert: MetalLBConfigNotLoaded
      annotations:
        message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container_name }} on {{ $labels.instance
          }} has not loaded for > 1 minute'`}}
      expr: metallb_k8s_client_config_loaded_bool{job="{{ .Values.prometheus.serviceMonitor.jobLabel }}"} == 0
      for: 1m
      labels:
        severity: warning
{{- end }} 
 # psp.yaml
{{- if .Values.psp.create -}}

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: {{ template "metallb.fullname" . }}-speaker
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
spec:
  hostNetwork: true
  hostPorts:
  - min: 7472
    max: 7472
  privileged: true
  allowPrivilegeEscalation: false
  allowedCapabilities:
  - 'NET_ADMIN'
  - 'NET_RAW'
  - 'SYS_ADMIN'
  volumes:
  - '*'
  fsGroup:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
{{- end -}}
 # rbac.yaml
{{- if .Values.rbac.create -}}

# Roles
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: {{ template "metallb.fullname" . }}:controller
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
rules:
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get", "list", "watch", "update"]
- apiGroups: [""]
  resources: ["services/status"]
  verbs: ["update"]
- apiGroups: [""]
  resources: ["events"]
  verbs: ["create", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: {{ template "metallb.fullname" . }}:speaker
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
rules:
- apiGroups: [""]
  resources: ["services", "endpoints", "nodes"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["events"]
  verbs: ["create", "patch"]
{{- if .Values.psp.create }}
- apiGroups: ["extensions"]
  resources: ["podsecuritypolicies"]
  resourceNames: [{{ printf "%s-speaker" (include "metallb.fullname" .) | quote}}]
  verbs: ["use"]
{{- end }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: {{ template "metallb.fullname" . }}-config-watcher
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list", "watch"]
---

## Role bindings
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: {{ template "metallb.fullname" . }}:controller
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
subjects:
- kind: ServiceAccount
  name: {{ template "metallb.controllerServiceAccountName" . }}
  namespace: {{ .Release.Namespace }}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: {{ template "metallb.fullname" . }}:controller
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: {{ template "metallb.fullname" . }}:speaker
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
subjects:
- kind: ServiceAccount
  name: {{ template "metallb.speakerServiceAccountName" . }}
  namespace: {{ .Release.Namespace }}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: {{ template "metallb.fullname" . }}:speaker
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: {{ template "metallb.fullname" . }}-config-watcher
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
subjects:
- kind: ServiceAccount
  name: {{ template "metallb.controllerServiceAccountName" . }}
- kind: ServiceAccount
  name: {{ template "metallb.speakerServiceAccountName" . }}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: {{ template "metallb.fullname" . }}-config-watcher
{{- end -}}
 # service-accounts.yaml
{{- if .Values.serviceAccounts.controller.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ template "metallb.controllerServiceAccountName" . }}
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
{{- end }}
---
{{- if .Values.serviceAccounts.speaker.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ template "metallb.speakerServiceAccountName" . }}
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
{{- end }}
 # service.yaml
{{- if .Values.prometheus.serviceMonitor.enabled }}
apiVersion: v1
kind: Service
metadata:
  name: {{ template "metallb.fullname" . }}-controller-metrics
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
    jobLabel: {{ .Values.prometheus.serviceMonitor.jobLabel }}
    component: controller
spec:
  type: ClusterIP
  selector:
    app: {{ template "metallb.name" . }}
    release: {{ .Release.Name | quote }}
    component: controller
  ports:
  - name: metrics
    port: 7472
    protocol: TCP
    targetPort: 7472
---
apiVersion: v1
kind: Service
metadata:
  name: {{ template "metallb.fullname" . }}-speaker-metrics
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
    jobLabel: {{ .Values.prometheus.serviceMonitor.jobLabel }}
    component: speaker
spec:
  type: ClusterIP
  selector:
    app: {{ template "metallb.name" . }}
    release: {{ .Release.Name | quote }}
    component: speaker
  ports:
  - name: metrics
    port: 7472
    protocol: TCP
    targetPort: 7472
{{- end }}
 # servicemonitor.yaml
{{- if .Values.prometheus.serviceMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: {{ template "metallb.fullname" . }}-controller
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
    component: controller
spec:
  jobLabel: jobLabel
  selector:
    matchLabels:
      app: {{ template "metallb.name" . }}
      release: {{ .Release.Name | quote }}
      component: controller
  namespaceSelector:
    matchNames:
    - {{ .Release.Namespace }}
  endpoints:
  - port: metrics
    {{- if .Values.prometheus.serviceMonitor.interval }}
    interval: {{ .Values.prometheus.serviceMonitor.interval }}
    {{- end }}
{{- if .Values.prometheus.serviceMonitor.metricRelabelings }}
    metricRelabelings:
{{ toYaml .Values.prometheus.serviceMonitor.metricRelabelings | indent 4 }}
{{- end }}
{{- if .Values.prometheus.serviceMonitor.relabelings }}
    relabelings:
{{ toYaml .Values.prometheus.serviceMonitor.relabelings | indent 4 }}
{{- end }}
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: {{ template "metallb.fullname" . }}-speaker
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
    component: speaker
spec:
  jobLabel: jobLabel
  selector:
    matchLabels:
      app: {{ template "metallb.name" . }}
      release: {{ .Release.Name | quote }}
      component: speaker
  namespaceSelector:
    matchNames:
    - {{ .Release.Namespace }}
  endpoints:
  - port: metrics
    {{- if .Values.prometheus.serviceMonitor.interval }}
    interval: {{ .Values.prometheus.serviceMonitor.interval }}
    {{- end }}
{{- if .Values.prometheus.serviceMonitor.metricRelabelings }}
    metricRelabelings:
{{ toYaml .Values.prometheus.serviceMonitor.metricRelabelings | indent 4 }}
{{- end }}
{{- if .Values.prometheus.serviceMonitor.relabelings }}
    relabelings:
{{ toYaml .Values.prometheus.serviceMonitor.relabelings | indent 4 }}
{{- end }}
{{- end }}
 # speaker.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: {{ template "metallb.fullname" . }}-speaker
  labels:
    heritage: {{ .Release.Service | quote }}
    release: {{ .Release.Name | quote }}
    chart: {{ template "metallb.chart" . }}
    app: {{ template "metallb.name" . }}
    component: speaker
spec:
  selector:
    matchLabels:
      app: {{ template "metallb.name" . }}
      component: speaker
      release: {{ .Release.Name | quote }}
  template:
    metadata:
      labels:
        heritage: {{ .Release.Service | quote }}
        release: {{ .Release.Name | quote }}
        chart: {{ template "metallb.chart" . }}
        app: {{ template "metallb.name" . }}
        component: speaker
{{- if .Values.prometheus.scrapeAnnotations }}
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "7472"
{{- end }}
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      serviceAccountName: {{ template "metallb.speakerServiceAccountName" . }}
      terminationGracePeriodSeconds: 0
      hostNetwork: true
{{- if gt (len .Values.speaker.initContainers) 0 }}
      initContainers:
{{ toYaml .Values.speaker.initContainers | indent 8 }}
{{- end }}
      containers:
      - name: speaker
        image: {{ .Values.speaker.image.repository }}:{{ .Values.speaker.image.tag }}
        imagePullPolicy: {{ .Values.speaker.image.pullPolicy }}
        args:
        - --port=7472
        - --config={{ template "metallb.configMapName" . }}
        env:
        - name: METALLB_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: METALLB_HOST
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        ports:
        - name: monitoring
          containerPort: 7472
        resources:
{{ toYaml .Values.speaker.resources | indent 10 }}
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities:
            drop:
            - ALL
            add:
            - NET_ADMIN
            - NET_RAW
            - SYS_ADMIN
      nodeSelector:
        "beta.kubernetes.io/os": linux
        {{- with .Values.speaker.nodeSelector }}
{{ toYaml . | indent 8 }}
    {{- end }}
    {{- with .Values.speaker.tolerations }}
      tolerations:
{{ toYaml . | indent 8 }}
    {{- end }}
    {{- with .Values.speaker.affinity }}
      affinity:
{{ toYaml . | indent 8 }}
    {{- end }}

# Default values for metallb.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

# To configure MetalLB, you must specify ONE of the following two
# options.

# existingConfigMap specifies the name of an externally-defined
# ConfigMap to use as the configuration. Helm will not manage the
# contents of this ConfigMap, it is your responsibility to create it.
existingConfigMap: metallb-config

# configInline specifies MetalLB's configuration directly, in yaml
# format. When configInline is used, Helm manages MetalLB's
# configuration ConfigMap as part of the release, and
# existingConfigMap is ignored.
#
# Refer to https://metallb.universe.tf/configuration/ for
# available options.
configInline: {}

rbac:
  # create specifies whether to install and use RBAC rules.
  create: true

psp:
  # create specifies whether to install and use Pod Security Policies.
  create: true

prometheus:
  # scrape annotations specifies whether to add Prometheus metric
  # auto-collection annotations to pods. See
  # https://github.com/prometheus/prometheus/blob/release-2.1/documentation/examples/prometheus-kubernetes.yml
  # for a corresponding Prometheus configuration. Alternatively, you
  # may want to use the Prometheus Operator
  # (https://github.com/coreos/prometheus-operator) for more powerful
  # monitoring configuration. If you use the Prometheus operator, this
  # can be left at false.
  scrapeAnnotations: false

  # Prometheus Operator service monitors
  serviceMonitor:

    # enable support for Prometheus Operator
    enabled: false

    # Job label for scrape target
    jobLabel: metallb

    # Scrape interval. If not set, the Prometheus default scrape interval is used.
    interval: ""

    # 	metric relabel configs to apply to samples before ingestion.
    metricRelabelings: []
    # - action: keep
    #   regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+'
    #   sourceLabels: [__name__]

    # 	relabel configs to apply to samples before ingestion.
    relabelings: []
    # - sourceLabels: [__meta_kubernetes_pod_node_name]
    #   separator: ;
    #   regex: ^(.*)$
    #   target_label: nodename
    #   replacement: $1
    #   action: replace

  # Prometheus Operator alertmanager alerts
  prometheusRule:

    # enable alertmanager alerts
    enabled: false


serviceAccounts:
  controller:
    # Specifies whether a ServiceAccount should be created
    create: true
    # The name of the ServiceAccount to use.  If not set and create is
    # true, a name is generated using the fullname template
    name: ""
  speaker:
    # Specifies whether a ServiceAccount should be created
    create: true
    # The name of the ServiceAccount to use.  If not set and create is
    # true, a name is generated using the fullname template
    name: ""

# controller contains configuration specific to the MetalLB cluster
# controller.
controller:
  image:
    repository: metallb/controller
    tag: v0.8.1
    pullPolicy: IfNotPresent
  resources: {}
    # limits:
      # cpu: 100m
      # memory: 100Mi
  nodeSelector: {}
  tolerations: []
  affinity: {}

# speaker contains configuration specific to the MetalLB speaker
# daemonset.
speaker:
  image:
    repository: metallb/speaker
    tag: v0.8.1
    pullPolicy: IfNotPresent
  resources: {}
    # limits:
      # cpu: 100m
      # memory: 100Mi
  nodeSelector: {}
  tolerations: []
  affinity: {}
  initContainers: []
