From b8e761f09a870d8b7d3b8a381744da418d629dfc Mon Sep 17 00:00:00 2001 From: Kristian Zhelyazkov Date: Thu, 10 Aug 2023 13:58:49 +0300 Subject: [PATCH] Add MetalLB chart --- assets/metallb/metallb-0.13.10.tgz | Bin 0 -> 24419 bytes charts/metallb/.helmignore | 23 + charts/metallb/Chart.lock | 6 + charts/metallb/Chart.yaml | 17 + charts/metallb/README.md | 158 +++ charts/metallb/charts/crds/.helmignore | 23 + charts/metallb/charts/crds/Chart.yaml | 10 + charts/metallb/charts/crds/README.md | 14 + .../metallb/charts/crds/templates/crds.yaml | 1233 +++++++++++++++++ charts/metallb/policy/controller.rego | 16 + charts/metallb/policy/rbac.rego | 27 + charts/metallb/policy/speaker.rego | 30 + charts/metallb/templates/NOTES.txt | 4 + charts/metallb/templates/_helpers.tpl | 113 ++ charts/metallb/templates/controller.yaml | 181 +++ .../templates/deprecated_configInline.yaml | 3 + .../metallb/templates/exclude-l2-config.yaml | 22 + charts/metallb/templates/podmonitor.yaml | 106 ++ charts/metallb/templates/prometheusrules.yaml | 84 ++ charts/metallb/templates/rbac.yaml | 206 +++ .../metallb/templates/service-accounts.yaml | 28 + charts/metallb/templates/servicemonitor.yaml | 188 +++ charts/metallb/templates/speaker.yaml | 505 +++++++ charts/metallb/templates/webhooks.yaml | 168 +++ charts/metallb/values.schema.json | 427 ++++++ charts/metallb/values.yaml | 342 +++++ index.html | 22 + index.yaml | 22 + 28 files changed, 3978 insertions(+) create mode 100644 assets/metallb/metallb-0.13.10.tgz create mode 100644 charts/metallb/.helmignore create mode 100644 charts/metallb/Chart.lock create mode 100644 charts/metallb/Chart.yaml create mode 100644 charts/metallb/README.md create mode 100644 charts/metallb/charts/crds/.helmignore create mode 100644 charts/metallb/charts/crds/Chart.yaml create mode 100644 charts/metallb/charts/crds/README.md create mode 100644 charts/metallb/charts/crds/templates/crds.yaml create mode 100644 charts/metallb/policy/controller.rego create mode 100644 charts/metallb/policy/rbac.rego create mode 100644 charts/metallb/policy/speaker.rego create mode 100644 charts/metallb/templates/NOTES.txt create mode 100644 charts/metallb/templates/_helpers.tpl create mode 100644 charts/metallb/templates/controller.yaml create mode 100644 charts/metallb/templates/deprecated_configInline.yaml create mode 100644 charts/metallb/templates/exclude-l2-config.yaml create mode 100644 charts/metallb/templates/podmonitor.yaml create mode 100644 charts/metallb/templates/prometheusrules.yaml create mode 100644 charts/metallb/templates/rbac.yaml create mode 100644 charts/metallb/templates/service-accounts.yaml create mode 100644 charts/metallb/templates/servicemonitor.yaml create mode 100644 charts/metallb/templates/speaker.yaml create mode 100644 charts/metallb/templates/webhooks.yaml create mode 100644 charts/metallb/values.schema.json create mode 100644 charts/metallb/values.yaml diff --git a/assets/metallb/metallb-0.13.10.tgz b/assets/metallb/metallb-0.13.10.tgz new file mode 100644 index 0000000000000000000000000000000000000000..24026e6e57ad377fe068d68a6119fd38325e5666 GIT binary patch literal 24419 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 literal 0 HcmV?d00001 diff --git a/charts/metallb/.helmignore b/charts/metallb/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/charts/metallb/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/metallb/Chart.lock b/charts/metallb/Chart.lock new file mode 100644 index 00000000..7d3b2e40 --- /dev/null +++ b/charts/metallb/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: crds + repository: "" + version: 0.13.10 +digest: sha256:afb2e9d5b709e7ded68c21f9d033a0a14a1232be270b0966e5ef2722575afc77 +generated: "2023-05-31T15:40:56.282100173+02:00" diff --git a/charts/metallb/Chart.yaml b/charts/metallb/Chart.yaml new file mode 100644 index 00000000..f7ffd3a8 --- /dev/null +++ b/charts/metallb/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +appVersion: v0.13.10 +dependencies: +- condition: crds.enabled + name: crds + repository: "" + version: 0.13.10 +description: A network load-balancer implementation for Kubernetes using standard + routing protocols +home: https://metallb.universe.tf +icon: https://metallb.universe.tf/images/logo/metallb-white.png +kubeVersion: '>= 1.19.0-0' +name: metallb +sources: +- https://github.com/metallb/metallb +type: application +version: 0.13.10 diff --git a/charts/metallb/README.md b/charts/metallb/README.md new file mode 100644 index 00000000..cacb69d2 --- /dev/null +++ b/charts/metallb/README.md @@ -0,0 +1,158 @@ +# metallb + +![Version: 0.13.10](https://img.shields.io/badge/Version-0.13.10-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.13.10](https://img.shields.io/badge/AppVersion-v0.13.10-informational?style=flat-square) + +A network load-balancer implementation for Kubernetes using standard routing protocols + +**Homepage:** + +## Source Code + +* + +## Requirements + +Kubernetes: `>= 1.19.0-0` + +| Repository | Name | Version | +|------------|------|---------| +| | crds | 0.13.10 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| controller.affinity | object | `{}` | | +| controller.enabled | bool | `true` | | +| controller.image.pullPolicy | string | `nil` | | +| controller.image.repository | string | `"quay.io/metallb/controller"` | | +| controller.image.tag | string | `nil` | | +| controller.labels | object | `{}` | | +| controller.livenessProbe.enabled | bool | `true` | | +| controller.livenessProbe.failureThreshold | int | `3` | | +| controller.livenessProbe.initialDelaySeconds | int | `10` | | +| controller.livenessProbe.periodSeconds | int | `10` | | +| controller.livenessProbe.successThreshold | int | `1` | | +| controller.livenessProbe.timeoutSeconds | int | `1` | | +| controller.logLevel | string | `"info"` | Controller log level. Must be one of: `all`, `debug`, `info`, `warn`, `error` or `none` | +| controller.nodeSelector | object | `{}` | | +| controller.podAnnotations | object | `{}` | | +| controller.priorityClassName | string | `""` | | +| controller.readinessProbe.enabled | bool | `true` | | +| controller.readinessProbe.failureThreshold | int | `3` | | +| controller.readinessProbe.initialDelaySeconds | int | `10` | | +| controller.readinessProbe.periodSeconds | int | `10` | | +| controller.readinessProbe.successThreshold | int | `1` | | +| controller.readinessProbe.timeoutSeconds | int | `1` | | +| controller.resources | object | `{}` | | +| controller.runtimeClassName | string | `""` | | +| controller.securityContext.fsGroup | int | `65534` | | +| controller.securityContext.runAsNonRoot | bool | `true` | | +| controller.securityContext.runAsUser | int | `65534` | | +| controller.serviceAccount.annotations | object | `{}` | | +| controller.serviceAccount.create | bool | `true` | | +| controller.serviceAccount.name | string | `""` | | +| controller.strategy.type | string | `"RollingUpdate"` | | +| controller.tolerations | list | `[]` | | +| crds.enabled | bool | `true` | | +| crds.validationFailurePolicy | string | `"Fail"` | | +| fullnameOverride | string | `""` | | +| imagePullSecrets | list | `[]` | | +| loadBalancerClass | string | `""` | | +| nameOverride | string | `""` | | +| prometheus.controllerMetricsTLSSecret | string | `""` | | +| prometheus.metricsPort | int | `7472` | | +| prometheus.namespace | string | `""` | | +| prometheus.podMonitor.additionalLabels | object | `{}` | | +| prometheus.podMonitor.annotations | object | `{}` | | +| prometheus.podMonitor.enabled | bool | `false` | | +| prometheus.podMonitor.interval | string | `nil` | | +| prometheus.podMonitor.jobLabel | string | `"app.kubernetes.io/name"` | | +| prometheus.podMonitor.metricRelabelings | list | `[]` | | +| prometheus.podMonitor.relabelings | list | `[]` | | +| prometheus.prometheusRule.additionalLabels | object | `{}` | | +| prometheus.prometheusRule.addressPoolExhausted.enabled | bool | `true` | | +| prometheus.prometheusRule.addressPoolExhausted.labels.severity | string | `"alert"` | | +| prometheus.prometheusRule.addressPoolUsage.enabled | bool | `true` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[0].labels.severity | string | `"warning"` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[0].percent | int | `75` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[1].labels.severity | string | `"warning"` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[1].percent | int | `85` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[2].labels.severity | string | `"alert"` | | +| prometheus.prometheusRule.addressPoolUsage.thresholds[2].percent | int | `95` | | +| prometheus.prometheusRule.annotations | object | `{}` | | +| prometheus.prometheusRule.bgpSessionDown.enabled | bool | `true` | | +| prometheus.prometheusRule.bgpSessionDown.labels.severity | string | `"alert"` | | +| prometheus.prometheusRule.configNotLoaded.enabled | bool | `true` | | +| prometheus.prometheusRule.configNotLoaded.labels.severity | string | `"warning"` | | +| prometheus.prometheusRule.enabled | bool | `false` | | +| prometheus.prometheusRule.extraAlerts | list | `[]` | | +| prometheus.prometheusRule.staleConfig.enabled | bool | `true` | | +| prometheus.prometheusRule.staleConfig.labels.severity | string | `"warning"` | | +| prometheus.rbacPrometheus | bool | `true` | | +| prometheus.rbacProxy.pullPolicy | string | `nil` | | +| prometheus.rbacProxy.repository | string | `"gcr.io/kubebuilder/kube-rbac-proxy"` | | +| prometheus.rbacProxy.tag | string | `"v0.12.0"` | | +| prometheus.scrapeAnnotations | bool | `false` | | +| prometheus.serviceAccount | string | `""` | | +| prometheus.serviceMonitor.controller.additionalLabels | object | `{}` | | +| prometheus.serviceMonitor.controller.annotations | object | `{}` | | +| prometheus.serviceMonitor.controller.tlsConfig.insecureSkipVerify | bool | `true` | | +| prometheus.serviceMonitor.enabled | bool | `false` | | +| prometheus.serviceMonitor.interval | string | `nil` | | +| prometheus.serviceMonitor.jobLabel | string | `"app.kubernetes.io/name"` | | +| prometheus.serviceMonitor.metricRelabelings | list | `[]` | | +| prometheus.serviceMonitor.relabelings | list | `[]` | | +| prometheus.serviceMonitor.speaker.additionalLabels | object | `{}` | | +| prometheus.serviceMonitor.speaker.annotations | object | `{}` | | +| prometheus.serviceMonitor.speaker.tlsConfig.insecureSkipVerify | bool | `true` | | +| prometheus.speakerMetricsTLSSecret | string | `""` | | +| rbac.create | bool | `true` | | +| speaker.affinity | object | `{}` | | +| speaker.enabled | bool | `true` | | +| speaker.excludeInterfaces.enabled | bool | `true` | | +| speaker.frr.enabled | bool | `true` | | +| speaker.frr.image.pullPolicy | string | `nil` | | +| speaker.frr.image.repository | string | `"quay.io/frrouting/frr"` | | +| speaker.frr.image.tag | string | `"8.4.2"` | | +| speaker.frr.metricsPort | int | `7473` | | +| speaker.frr.resources | object | `{}` | | +| speaker.frrMetrics.resources | object | `{}` | | +| speaker.image.pullPolicy | string | `nil` | | +| speaker.image.repository | string | `"quay.io/metallb/speaker"` | | +| speaker.image.tag | string | `nil` | | +| speaker.labels | object | `{}` | | +| speaker.livenessProbe.enabled | bool | `true` | | +| speaker.livenessProbe.failureThreshold | int | `3` | | +| speaker.livenessProbe.initialDelaySeconds | int | `10` | | +| speaker.livenessProbe.periodSeconds | int | `10` | | +| speaker.livenessProbe.successThreshold | int | `1` | | +| speaker.livenessProbe.timeoutSeconds | int | `1` | | +| speaker.logLevel | string | `"info"` | Speaker log level. Must be one of: `all`, `debug`, `info`, `warn`, `error` or `none` | +| speaker.memberlist.enabled | bool | `true` | | +| speaker.memberlist.mlBindPort | int | `7946` | | +| speaker.memberlist.mlSecretKeyPath | string | `"/etc/ml_secret_key"` | | +| speaker.nodeSelector | object | `{}` | | +| speaker.podAnnotations | object | `{}` | | +| speaker.priorityClassName | string | `""` | | +| speaker.readinessProbe.enabled | bool | `true` | | +| speaker.readinessProbe.failureThreshold | int | `3` | | +| speaker.readinessProbe.initialDelaySeconds | int | `10` | | +| speaker.readinessProbe.periodSeconds | int | `10` | | +| speaker.readinessProbe.successThreshold | int | `1` | | +| speaker.readinessProbe.timeoutSeconds | int | `1` | | +| speaker.reloader.resources | object | `{}` | | +| speaker.resources | object | `{}` | | +| speaker.runtimeClassName | string | `""` | | +| speaker.serviceAccount.annotations | object | `{}` | | +| speaker.serviceAccount.create | bool | `true` | | +| speaker.serviceAccount.name | string | `""` | | +| speaker.startupProbe.enabled | bool | `true` | | +| speaker.startupProbe.failureThreshold | int | `30` | | +| speaker.startupProbe.periodSeconds | int | `5` | | +| speaker.tolerateMaster | bool | `true` | | +| speaker.tolerations | list | `[]` | | +| speaker.updateStrategy.type | string | `"RollingUpdate"` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.10.0](https://github.com/norwoodj/helm-docs/releases/v1.10.0) diff --git a/charts/metallb/charts/crds/.helmignore b/charts/metallb/charts/crds/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/charts/metallb/charts/crds/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/metallb/charts/crds/Chart.yaml b/charts/metallb/charts/crds/Chart.yaml new file mode 100644 index 00000000..0b504402 --- /dev/null +++ b/charts/metallb/charts/crds/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +appVersion: v0.13.10 +description: MetalLB CRDs +home: https://metallb.universe.tf +icon: https://metallb.universe.tf/images/logo/metallb-white.png +name: crds +sources: +- https://github.com/metallb/metallb +type: application +version: 0.13.10 diff --git a/charts/metallb/charts/crds/README.md b/charts/metallb/charts/crds/README.md new file mode 100644 index 00000000..18f80eb0 --- /dev/null +++ b/charts/metallb/charts/crds/README.md @@ -0,0 +1,14 @@ +# crds + +![Version: 0.13.10](https://img.shields.io/badge/Version-0.13.10-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.13.10](https://img.shields.io/badge/AppVersion-v0.13.10-informational?style=flat-square) + +MetalLB CRDs + +**Homepage:** + +## Source Code + +* + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.10.0](https://github.com/norwoodj/helm-docs/releases/v1.10.0) diff --git a/charts/metallb/charts/crds/templates/crds.yaml b/charts/metallb/charts/crds/templates/crds.yaml new file mode 100644 index 00000000..9b415acf --- /dev/null +++ b/charts/metallb/charts/crds/templates/crds.yaml @@ -0,0 +1,1233 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + name: addresspools.metallb.io +spec: + group: metallb.io + names: + kind: AddressPool + listKind: AddressPoolList + plural: addresspools + singular: addresspool + scope: Namespaced + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1alpha1", "v1beta1"] + clientConfig: + # this is a valid pem format, otherwise the apiserver will reject the deletion of the crds + # with "unable to parse bytes as PEM block", The controller will patch it with the right content after it starts + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlGWlRDQ0EwMmdBd0lCQWdJVU5GRW1XcTM3MVpKdGkrMmlSQzk1WmpBV1MxZ3dEUVlKS29aSWh2Y05BUUVMDQpCUUF3UWpFTE1Ba0dBMVVFQmhNQ1dGZ3hGVEFUQmdOVkJBY01ERVJsWm1GMWJIUWdRMmwwZVRFY01Cb0dBMVVFDQpDZ3dUUkdWbVlYVnNkQ0JEYjIxd1lXNTVJRXgwWkRBZUZ3MHlNakEzTVRrd09UTXlNek5hRncweU1qQTRNVGd3DQpPVE15TXpOYU1FSXhDekFKQmdOVkJBWVRBbGhZTVJVd0V3WURWUVFIREF4RVpXWmhkV3gwSUVOcGRIa3hIREFhDQpCZ05WQkFvTUUwUmxabUYxYkhRZ1EyOXRjR0Z1ZVNCTWRHUXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDDQpEd0F3Z2dJS0FvSUNBUUNxVFpxMWZRcC9vYkdlenhES0o3OVB3Ny94azJwellualNzMlkzb1ZYSm5sRmM4YjVlDQpma2ZZQnY2bndscW1keW5PL2phWFBaQmRQSS82aFdOUDBkdVhadEtWU0NCUUpyZzEyOGNXb3F0MGNTN3pLb1VpDQpvcU1tQ0QvRXVBeFFNZjhRZDF2c1gvVllkZ0poVTZBRXJLZEpIaXpFOUJtUkNkTDBGMW1OVW55Rk82UnRtWFZUDQpidkxsTDVYeTc2R0FaQVBLOFB4aVlDa0NtbDdxN0VnTWNiOXlLWldCYmlxQ3VkTXE5TGJLNmdKNzF6YkZnSXV4DQo1L1pXK2JraTB2RlplWk9ZODUxb1psckFUNzJvMDI4NHNTWW9uN0pHZVZkY3NoUnh5R1VpSFpSTzdkaXZVTDVTDQpmM2JmSDFYbWY1ZDQzT0NWTWRuUUV2NWVaOG8zeWVLa3ZrbkZQUGVJMU9BbjdGbDlFRVNNR2dhOGFaSG1URSttDQpsLzlMSmdDYjBnQmtPT0M0WnV4bWh2aERKV1EzWnJCS3pMQlNUZXN0NWlLNVlwcXRWVVk2THRyRW9FelVTK1lsDQpwWndXY2VQWHlHeHM5ZURsR3lNVmQraW15Y3NTU1UvVno2Mmx6MnZCS21NTXBkYldDQWhud0RsRTVqU2dyMjRRDQp0eGNXLys2N3d5KzhuQlI3UXdqVTFITndVRjBzeERWdEwrZ1NHVERnSEVZSlhZelYvT05zMy94TkpoVFNPSkxNDQpoeXNVdyttaGdackdhbUdXcHVIVU1DUitvTWJzMTc1UkcrQjJnUFFHVytPTjJnUTRyOXN2b0ZBNHBBQm8xd1dLDQpRYjRhY3pmeVVscElBOVFoSmFsZEY3S3dPSHVlV3gwRUNrNXg0T2tvVDBvWVp0dzFiR0JjRGtaSmF3SURBUUFCDQpvMU13VVRBZEJnTlZIUTRFRmdRVW90UlNIUm9IWTEyRFZ4R0NCdEhpb1g2ZmVFQXdId1lEVlIwakJCZ3dGb0FVDQpvdFJTSFJvSFkxMkRWeEdDQnRIaW9YNmZlRUF3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCDQpBUXNGQUFPQ0FnRUFSbkpsWWRjMTFHd0VxWnh6RDF2R3BDR2pDN2VWTlQ3aVY1d3IybXlybHdPYi9aUWFEa0xYDQpvVStaOVVXT1VlSXJTdzUydDdmQUpvVVAwSm5iYkMveVIrU1lqUGhvUXNiVHduOTc2ZldBWTduM3FMOXhCd1Y0DQphek41OXNjeUp0dlhMeUtOL2N5ak1ReDRLajBIMFg0bWJ6bzVZNUtzWWtYVU0vOEFPdWZMcEd0S1NGVGgrSEFDDQpab1Q5YnZHS25adnNHd0tYZFF0Wnh0akhaUjVqK3U3ZGtQOTJBT051RFNabS8rWVV4b2tBK09JbzdSR3BwSHNXDQo1ZTdNY0FTVXRtb1FORXd6dVFoVkJaRWQ1OGtKYjUrV0VWbGNzanlXNnRTbzErZ25tTWNqR1BsMWgxR2hVbjV4DQpFY0lWRnBIWXM5YWo1NmpBSjk1MVQvZjhMaWxmTlVnanBLQ0c1bnl0SUt3emxhOHNtdGlPdm1UNEpYbXBwSkI2DQo4bmdHRVluVjUrUTYwWFJ2OEhSSGp1VG9CRHVhaERrVDA2R1JGODU1d09FR2V4bkZpMXZYWUxLVllWb1V2MXRKDQo4dVdUR1pwNllDSVJldlBqbzg5ZytWTlJSaVFYUThJd0dybXE5c0RoVTlqTjA0SjdVL1RvRDFpNHE3VnlsRUc5DQorV1VGNkNLaEdBeTJIaEhwVncyTGFoOS9lUzdZMUZ1YURrWmhPZG1laG1BOCtqdHNZamJadnR5Mm1SWlF0UUZzDQpUU1VUUjREbUR2bVVPRVRmeStpRHdzK2RkWXVNTnJGeVVYV2dkMnpBQU4ydVl1UHFGY2pRcFNPODFzVTJTU3R3DQoxVzAyeUtYOGJEYmZFdjBzbUh3UzliQnFlSGo5NEM1Mjg0YXpsdTBmaUdpTm1OUEM4ckJLRmhBPQ0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ== + service: + namespace: {{ .Release.Namespace }} + name: metallb-webhook-service + path: /convert + versions: + - deprecated: true + deprecationWarning: metallb.io v1alpha1 AddressPool is deprecated + name: v1alpha1 + schema: + openAPIV3Schema: + description: AddressPool is the Schema for the addresspools API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AddressPoolSpec defines the desired state of AddressPool. + properties: + addresses: + description: A list of IP address ranges over which MetalLB has authority. + You can list multiple ranges in a single pool, they will all share + the same settings. Each range can be either a CIDR prefix, or an + explicit start-end range of IPs. + items: + type: string + type: array + autoAssign: + default: true + description: AutoAssign flag used to prevent MetallB from automatic + allocation for a pool. + type: boolean + bgpAdvertisements: + description: When an IP is allocated from this pool, how should it + be translated into BGP announcements? + items: + properties: + aggregationLength: + default: 32 + description: The aggregation-length advertisement option lets + you “roll up” the /32s into a larger prefix. + format: int32 + minimum: 1 + type: integer + aggregationLengthV6: + default: 128 + description: Optional, defaults to 128 (i.e. no aggregation) + if not specified. + format: int32 + type: integer + communities: + description: BGP communities + items: + type: string + type: array + localPref: + description: BGP LOCAL_PREF attribute which is used by BGP best + path algorithm, Path with higher localpref is preferred over + one with lower localpref. + format: int32 + type: integer + type: object + type: array + protocol: + description: Protocol can be used to select how the announcement is + done. + enum: + - layer2 + - bgp + type: string + required: + - addresses + - protocol + type: object + status: + description: AddressPoolStatus defines the observed state of AddressPool. + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} + - deprecated: true + deprecationWarning: metallb.io v1beta1 AddressPool is deprecated, consider using + IPAddressPool + name: v1beta1 + schema: + openAPIV3Schema: + description: AddressPool represents a pool of IP addresses that can be allocated + to LoadBalancer services. AddressPool is deprecated and being replaced by + IPAddressPool. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AddressPoolSpec defines the desired state of AddressPool. + properties: + addresses: + description: A list of IP address ranges over which MetalLB has authority. + You can list multiple ranges in a single pool, they will all share + the same settings. Each range can be either a CIDR prefix, or an + explicit start-end range of IPs. + items: + type: string + type: array + autoAssign: + default: true + description: AutoAssign flag used to prevent MetallB from automatic + allocation for a pool. + type: boolean + bgpAdvertisements: + description: Drives how an IP allocated from this pool should translated + into BGP announcements. + items: + properties: + aggregationLength: + default: 32 + description: The aggregation-length advertisement option lets + you “roll up” the /32s into a larger prefix. + format: int32 + minimum: 1 + type: integer + aggregationLengthV6: + default: 128 + description: Optional, defaults to 128 (i.e. no aggregation) + if not specified. + format: int32 + type: integer + communities: + description: BGP communities to be associated with the given + advertisement. + items: + type: string + type: array + localPref: + description: BGP LOCAL_PREF attribute which is used by BGP best + path algorithm, Path with higher localpref is preferred over + one with lower localpref. + format: int32 + type: integer + type: object + type: array + protocol: + description: Protocol can be used to select how the announcement is + done. + enum: + - layer2 + - bgp + type: string + required: + - addresses + - protocol + type: object + status: + description: AddressPoolStatus defines the observed state of AddressPool. + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + name: bfdprofiles.metallb.io +spec: + group: metallb.io + names: + kind: BFDProfile + listKind: BFDProfileList + plural: bfdprofiles + singular: bfdprofile + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: BFDProfile represents the settings of the bfd session that can + be optionally associated with a BGP session. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BFDProfileSpec defines the desired state of BFDProfile. + properties: + detectMultiplier: + description: Configures the detection multiplier to determine packet + loss. The remote transmission interval will be multiplied by this + value to determine the connection loss detection timer. + format: int32 + maximum: 255 + minimum: 2 + type: integer + echoInterval: + description: Configures the minimal echo receive transmission interval + that this system is capable of handling in milliseconds. Defaults + to 50ms + format: int32 + maximum: 60000 + minimum: 10 + type: integer + echoMode: + description: Enables or disables the echo transmission mode. This + mode is disabled by default, and not supported on multi hops setups. + type: boolean + minimumTtl: + description: 'For multi hop sessions only: configure the minimum expected + TTL for an incoming BFD control packet.' + format: int32 + maximum: 254 + minimum: 1 + type: integer + passiveMode: + description: 'Mark session as passive: a passive session will not + attempt to start the connection and will wait for control packets + from peer before it begins replying.' + type: boolean + receiveInterval: + description: The minimum interval that this system is capable of receiving + control packets in milliseconds. Defaults to 300ms. + format: int32 + maximum: 60000 + minimum: 10 + type: integer + transmitInterval: + description: The minimum transmission interval (less jitter) that + this system wants to use to send BFD control packets in milliseconds. + Defaults to 300ms + format: int32 + maximum: 60000 + minimum: 10 + type: integer + type: object + status: + description: BFDProfileStatus defines the observed state of BFDProfile. + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + name: bgpadvertisements.metallb.io +spec: + group: metallb.io + names: + kind: BGPAdvertisement + listKind: BGPAdvertisementList + plural: bgpadvertisements + singular: bgpadvertisement + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: BGPAdvertisement allows to advertise the IPs coming from the + selected IPAddressPools via BGP, setting the parameters of the BGP Advertisement. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BGPAdvertisementSpec defines the desired state of BGPAdvertisement. + properties: + aggregationLength: + default: 32 + description: The aggregation-length advertisement option lets you + “roll up” the /32s into a larger prefix. Defaults to 32. Works for + IPv4 addresses. + format: int32 + minimum: 1 + type: integer + aggregationLengthV6: + default: 128 + description: The aggregation-length advertisement option lets you + “roll up” the /128s into a larger prefix. Defaults to 128. Works + for IPv6 addresses. + format: int32 + type: integer + communities: + description: The BGP communities to be associated with the announcement. + Each item can be a community of the form 1234:1234 or the name of + an alias defined in the Community CRD. + items: + type: string + type: array + ipAddressPoolSelectors: + description: A selector for the IPAddressPools which would get advertised + via this advertisement. If no IPAddressPool is selected by this + or by the list, the advertisement is applied to all the IPAddressPools. + items: + description: A label selector is a label query over a set of resources. + The result of matchLabels and matchExpressions are ANDed. An empty + label selector matches all objects. A null label selector matches + no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + type: array + ipAddressPools: + description: The list of IPAddressPools to advertise via this advertisement, + selected by name. + items: + type: string + type: array + localPref: + description: The BGP LOCAL_PREF attribute which is used by BGP best + path algorithm, Path with higher localpref is preferred over one + with lower localpref. + format: int32 + type: integer + nodeSelectors: + description: NodeSelectors allows to limit the nodes to announce as + next hops for the LoadBalancer IP. When empty, all the nodes having are + announced as next hops. + items: + description: A label selector is a label query over a set of resources. + The result of matchLabels and matchExpressions are ANDed. An empty + label selector matches all objects. A null label selector matches + no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + type: array + peers: + description: Peers limits the bgppeer to advertise the ips of the + selected pools to. When empty, the loadbalancer IP is announced + to all the BGPPeers configured. + items: + type: string + type: array + type: object + status: + description: BGPAdvertisementStatus defines the observed state of BGPAdvertisement. + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + name: bgppeers.metallb.io +spec: + group: metallb.io + names: + kind: BGPPeer + listKind: BGPPeerList + plural: bgppeers + singular: bgppeer + scope: Namespaced + conversion: + strategy: Webhook + webhook: + conversionReviewVersions: ["v1beta1", "v1beta2"] + clientConfig: + # this is a valid pem format, otherwise the apiserver will reject the deletion of the crds + # with "unable to parse bytes as PEM block", The controller will patch it with the right content after it starts + caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlGWlRDQ0EwMmdBd0lCQWdJVU5GRW1XcTM3MVpKdGkrMmlSQzk1WmpBV1MxZ3dEUVlKS29aSWh2Y05BUUVMDQpCUUF3UWpFTE1Ba0dBMVVFQmhNQ1dGZ3hGVEFUQmdOVkJBY01ERVJsWm1GMWJIUWdRMmwwZVRFY01Cb0dBMVVFDQpDZ3dUUkdWbVlYVnNkQ0JEYjIxd1lXNTVJRXgwWkRBZUZ3MHlNakEzTVRrd09UTXlNek5hRncweU1qQTRNVGd3DQpPVE15TXpOYU1FSXhDekFKQmdOVkJBWVRBbGhZTVJVd0V3WURWUVFIREF4RVpXWmhkV3gwSUVOcGRIa3hIREFhDQpCZ05WQkFvTUUwUmxabUYxYkhRZ1EyOXRjR0Z1ZVNCTWRHUXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDDQpEd0F3Z2dJS0FvSUNBUUNxVFpxMWZRcC9vYkdlenhES0o3OVB3Ny94azJwellualNzMlkzb1ZYSm5sRmM4YjVlDQpma2ZZQnY2bndscW1keW5PL2phWFBaQmRQSS82aFdOUDBkdVhadEtWU0NCUUpyZzEyOGNXb3F0MGNTN3pLb1VpDQpvcU1tQ0QvRXVBeFFNZjhRZDF2c1gvVllkZ0poVTZBRXJLZEpIaXpFOUJtUkNkTDBGMW1OVW55Rk82UnRtWFZUDQpidkxsTDVYeTc2R0FaQVBLOFB4aVlDa0NtbDdxN0VnTWNiOXlLWldCYmlxQ3VkTXE5TGJLNmdKNzF6YkZnSXV4DQo1L1pXK2JraTB2RlplWk9ZODUxb1psckFUNzJvMDI4NHNTWW9uN0pHZVZkY3NoUnh5R1VpSFpSTzdkaXZVTDVTDQpmM2JmSDFYbWY1ZDQzT0NWTWRuUUV2NWVaOG8zeWVLa3ZrbkZQUGVJMU9BbjdGbDlFRVNNR2dhOGFaSG1URSttDQpsLzlMSmdDYjBnQmtPT0M0WnV4bWh2aERKV1EzWnJCS3pMQlNUZXN0NWlLNVlwcXRWVVk2THRyRW9FelVTK1lsDQpwWndXY2VQWHlHeHM5ZURsR3lNVmQraW15Y3NTU1UvVno2Mmx6MnZCS21NTXBkYldDQWhud0RsRTVqU2dyMjRRDQp0eGNXLys2N3d5KzhuQlI3UXdqVTFITndVRjBzeERWdEwrZ1NHVERnSEVZSlhZelYvT05zMy94TkpoVFNPSkxNDQpoeXNVdyttaGdackdhbUdXcHVIVU1DUitvTWJzMTc1UkcrQjJnUFFHVytPTjJnUTRyOXN2b0ZBNHBBQm8xd1dLDQpRYjRhY3pmeVVscElBOVFoSmFsZEY3S3dPSHVlV3gwRUNrNXg0T2tvVDBvWVp0dzFiR0JjRGtaSmF3SURBUUFCDQpvMU13VVRBZEJnTlZIUTRFRmdRVW90UlNIUm9IWTEyRFZ4R0NCdEhpb1g2ZmVFQXdId1lEVlIwakJCZ3dGb0FVDQpvdFJTSFJvSFkxMkRWeEdDQnRIaW9YNmZlRUF3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCDQpBUXNGQUFPQ0FnRUFSbkpsWWRjMTFHd0VxWnh6RDF2R3BDR2pDN2VWTlQ3aVY1d3IybXlybHdPYi9aUWFEa0xYDQpvVStaOVVXT1VlSXJTdzUydDdmQUpvVVAwSm5iYkMveVIrU1lqUGhvUXNiVHduOTc2ZldBWTduM3FMOXhCd1Y0DQphek41OXNjeUp0dlhMeUtOL2N5ak1ReDRLajBIMFg0bWJ6bzVZNUtzWWtYVU0vOEFPdWZMcEd0S1NGVGgrSEFDDQpab1Q5YnZHS25adnNHd0tYZFF0Wnh0akhaUjVqK3U3ZGtQOTJBT051RFNabS8rWVV4b2tBK09JbzdSR3BwSHNXDQo1ZTdNY0FTVXRtb1FORXd6dVFoVkJaRWQ1OGtKYjUrV0VWbGNzanlXNnRTbzErZ25tTWNqR1BsMWgxR2hVbjV4DQpFY0lWRnBIWXM5YWo1NmpBSjk1MVQvZjhMaWxmTlVnanBLQ0c1bnl0SUt3emxhOHNtdGlPdm1UNEpYbXBwSkI2DQo4bmdHRVluVjUrUTYwWFJ2OEhSSGp1VG9CRHVhaERrVDA2R1JGODU1d09FR2V4bkZpMXZYWUxLVllWb1V2MXRKDQo4dVdUR1pwNllDSVJldlBqbzg5ZytWTlJSaVFYUThJd0dybXE5c0RoVTlqTjA0SjdVL1RvRDFpNHE3VnlsRUc5DQorV1VGNkNLaEdBeTJIaEhwVncyTGFoOS9lUzdZMUZ1YURrWmhPZG1laG1BOCtqdHNZamJadnR5Mm1SWlF0UUZzDQpUU1VUUjREbUR2bVVPRVRmeStpRHdzK2RkWXVNTnJGeVVYV2dkMnpBQU4ydVl1UHFGY2pRcFNPODFzVTJTU3R3DQoxVzAyeUtYOGJEYmZFdjBzbUh3UzliQnFlSGo5NEM1Mjg0YXpsdTBmaUdpTm1OUEM4ckJLRmhBPQ0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ== + service: + namespace: {{ .Release.Namespace }} + name: metallb-webhook-service + path: /convert + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: BGPPeer is the Schema for the peers API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BGPPeerSpec defines the desired state of Peer. + properties: + bfdProfile: + type: string + ebgpMultiHop: + description: EBGP peer is multi-hops away + type: boolean + holdTime: + description: Requested BGP hold time, per RFC4271. + type: string + keepaliveTime: + description: Requested BGP keepalive time, per RFC4271. + type: string + myASN: + description: AS number to use for the local end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + nodeSelectors: + description: Only connect to this peer on nodes that match one of + these selectors. + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + minItems: 1 + type: array + required: + - key + - operator + - values + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: array + password: + description: Authentication password for routers enforcing TCP MD5 + authenticated sessions + type: string + peerASN: + description: AS number to expect from the remote end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + peerAddress: + description: Address to dial when establishing the session. + type: string + peerPort: + description: Port to dial when establishing the session. + maximum: 16384 + minimum: 0 + type: integer + routerID: + description: BGP router ID to advertise to the peer + type: string + sourceAddress: + description: Source address to use when establishing the session. + type: string + required: + - myASN + - peerASN + - peerAddress + type: object + status: + description: BGPPeerStatus defines the observed state of Peer. + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1beta2 + schema: + openAPIV3Schema: + description: BGPPeer is the Schema for the peers API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BGPPeerSpec defines the desired state of Peer. + properties: + bfdProfile: + description: The name of the BFD Profile to be used for the BFD session + associated to the BGP session. If not set, the BFD session won't + be set up. + type: string + ebgpMultiHop: + description: To set if the BGPPeer is multi-hops away. Needed for + FRR mode only. + type: boolean + holdTime: + description: Requested BGP hold time, per RFC4271. + type: string + keepaliveTime: + description: Requested BGP keepalive time, per RFC4271. + type: string + myASN: + description: AS number to use for the local end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + nodeSelectors: + description: Only connect to this peer on nodes that match one of + these selectors. + items: + description: A label selector is a label query over a set of resources. + The result of matchLabels and matchExpressions are ANDed. An empty + label selector matches all objects. A null label selector matches + no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + type: array + password: + description: Authentication password for routers enforcing TCP MD5 + authenticated sessions + type: string + passwordSecret: + description: passwordSecret is name of the authentication secret for + BGP Peer. the secret must be of type "kubernetes.io/basic-auth", + and created in the same namespace as the MetalLB deployment. The + password is stored in the secret as the key "password". + properties: + name: + description: Name is unique within a namespace to reference a + secret resource. + type: string + namespace: + description: Namespace defines the space within which the secret + name must be unique. + type: string + type: object + peerASN: + description: AS number to expect from the remote end of the session. + format: int32 + maximum: 4294967295 + minimum: 0 + type: integer + peerAddress: + description: Address to dial when establishing the session. + type: string + peerPort: + default: 179 + description: Port to dial when establishing the session. + maximum: 16384 + minimum: 0 + type: integer + routerID: + description: BGP router ID to advertise to the peer + type: string + sourceAddress: + description: Source address to use when establishing the session. + type: string + vrf: + description: To set if we want to peer with the BGPPeer using an interface + belonging to a host vrf + type: string + required: + - myASN + - peerASN + - peerAddress + type: object + status: + description: BGPPeerStatus defines the observed state of Peer. + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + name: ipaddresspools.metallb.io +spec: + group: metallb.io + names: + kind: IPAddressPool + listKind: IPAddressPoolList + plural: ipaddresspools + singular: ipaddresspool + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: IPAddressPool represents a pool of IP addresses that can be allocated + to LoadBalancer services. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: IPAddressPoolSpec defines the desired state of IPAddressPool. + properties: + addresses: + description: A list of IP address ranges over which MetalLB has authority. + You can list multiple ranges in a single pool, they will all share + the same settings. Each range can be either a CIDR prefix, or an + explicit start-end range of IPs. + items: + type: string + type: array + autoAssign: + default: true + description: AutoAssign flag used to prevent MetallB from automatic + allocation for a pool. + type: boolean + avoidBuggyIPs: + default: false + description: AvoidBuggyIPs prevents addresses ending with .0 and .255 + to be used by a pool. + type: boolean + serviceAllocation: + description: AllocateTo makes ip pool allocation to specific namespace + and/or service. The controller will use the pool with lowest value + of priority in case of multiple matches. A pool with no priority + set will be used only if the pools with priority can't be used. + If multiple matching IPAddressPools are available it will check + for the availability of IPs sorting the matching IPAddressPools + by priority, starting from the highest to the lowest. If multiple + IPAddressPools have the same priority, choice will be random. + properties: + namespaceSelectors: + description: NamespaceSelectors list of label selectors to select + namespace(s) for ip pool, an alternative to using namespace + list. + items: + description: A label selector is a label query over a set of + resources. The result of matchLabels and matchExpressions + are ANDed. An empty label selector matches all objects. A + null label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. This + array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field is + "key", the operator is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + type: array + namespaces: + description: Namespaces list of namespace(s) on which ip pool + can be attached. + items: + type: string + type: array + priority: + description: Priority priority given for ip pool while ip allocation + on a service. + type: integer + serviceSelectors: + description: ServiceSelectors list of label selector to select + service(s) for which ip pool can be used for ip allocation. + items: + description: A label selector is a label query over a set of + resources. The result of matchLabels and matchExpressions + are ANDed. An empty label selector matches all objects. A + null label selector matches no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. This + array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field is + "key", the operator is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + type: array + type: object + required: + - addresses + type: object + status: + description: IPAddressPoolStatus defines the observed state of IPAddressPool. + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + name: l2advertisements.metallb.io +spec: + group: metallb.io + names: + kind: L2Advertisement + listKind: L2AdvertisementList + plural: l2advertisements + singular: l2advertisement + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: L2Advertisement allows to advertise the LoadBalancer IPs provided + by the selected pools via L2. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: L2AdvertisementSpec defines the desired state of L2Advertisement. + properties: + interfaces: + description: A list of interfaces to announce from. The LB IP will + be announced only from these interfaces. If the field is not set, + we advertise from all the interfaces on the host. + items: + type: string + type: array + ipAddressPoolSelectors: + description: A selector for the IPAddressPools which would get advertised + via this advertisement. If no IPAddressPool is selected by this + or by the list, the advertisement is applied to all the IPAddressPools. + items: + description: A label selector is a label query over a set of resources. + The result of matchLabels and matchExpressions are ANDed. An empty + label selector matches all objects. A null label selector matches + no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + type: array + ipAddressPools: + description: The list of IPAddressPools to advertise via this advertisement, + selected by name. + items: + type: string + type: array + nodeSelectors: + description: NodeSelectors allows to limit the nodes to announce as + next hops for the LoadBalancer IP. When empty, all the nodes having are + announced as next hops. + items: + description: A label selector is a label query over a set of resources. + The result of matchLabels and matchExpressions are ANDed. An empty + label selector matches all objects. A null label selector matches + no objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + type: array + type: object + status: + description: L2AdvertisementStatus defines the observed state of L2Advertisement. + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.7.0 + creationTimestamp: null + name: communities.metallb.io +spec: + group: metallb.io + names: + kind: Community + listKind: CommunityList + plural: communities + singular: community + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: Community is a collection of aliases for communities. Users can + define named aliases to be used in the BGPPeer CRD. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: CommunitySpec defines the desired state of Community. + properties: + communities: + items: + properties: + name: + description: The name of the alias for the community. + type: string + value: + description: The BGP community value corresponding to the given + name. + type: string + type: object + type: array + type: object + status: + description: CommunityStatus defines the observed state of Community. + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/charts/metallb/policy/controller.rego b/charts/metallb/policy/controller.rego new file mode 100644 index 00000000..716eeb7a --- /dev/null +++ b/charts/metallb/policy/controller.rego @@ -0,0 +1,16 @@ +package main + +# validate serviceAccountName +deny[msg] { + input.kind == "Deployment" + serviceAccountName := input.spec.template.spec.serviceAccountName + not serviceAccountName == "RELEASE-NAME-metallb-controller" + msg = sprintf("controller serviceAccountName '%s' does not match expected value", [serviceAccountName]) +} + +# validate node selector includes builtin when custom ones are provided +deny[msg] { + input.kind == "Deployment" + not input.spec.template.spec.nodeSelector["kubernetes.io/os"] == "linux" + msg = "controller nodeSelector does not include '\"kubernetes.io/os\": linux'" +} diff --git a/charts/metallb/policy/rbac.rego b/charts/metallb/policy/rbac.rego new file mode 100644 index 00000000..047345eb --- /dev/null +++ b/charts/metallb/policy/rbac.rego @@ -0,0 +1,27 @@ +package main + +# Validate PSP exists in ClusterRole :controller +deny[msg] { + input.kind == "ClusterRole" + input.metadata.name == "metallb:controller" + input.rules[3] == { + "apiGroups": ["policy"], + "resources": ["podsecuritypolicies"], + "resourceNames": ["metallb-controller"], + "verbs": ["use"] + } + msg = "ClusterRole metallb:controller does not include PSP rule" +} + +# Validate PSP exists in ClusterRole :speaker +deny[msg] { + input.kind == "ClusterRole" + input.metadata.name == "metallb:speaker" + input.rules[3] == { + "apiGroups": ["policy"], + "resources": ["podsecuritypolicies"], + "resourceNames": ["metallb-controller"], + "verbs": ["use"] + } + msg = "ClusterRole metallb:speaker does not include PSP rule" +} diff --git a/charts/metallb/policy/speaker.rego b/charts/metallb/policy/speaker.rego new file mode 100644 index 00000000..d4d8137f --- /dev/null +++ b/charts/metallb/policy/speaker.rego @@ -0,0 +1,30 @@ +package main + +# validate serviceAccountName +deny[msg] { + input.kind == "DaemonSet" + serviceAccountName := input.spec.template.spec.serviceAccountName + not serviceAccountName == "RELEASE-NAME-metallb-speaker" + msg = sprintf("speaker serviceAccountName '%s' does not match expected value", [serviceAccountName]) +} + +# validate METALLB_ML_SECRET_KEY (memberlist) +deny[msg] { + input.kind == "DaemonSet" + not input.spec.template.spec.containers[0].env[5].name == "METALLB_ML_SECRET_KEY_PATH" + msg = "speaker env does not contain METALLB_ML_SECRET_KEY_PATH at env[5]" +} + +# validate node selector includes builtin when custom ones are provided +deny[msg] { + input.kind == "DaemonSet" + not input.spec.template.spec.nodeSelector["kubernetes.io/os"] == "linux" + msg = "controller nodeSelector does not include '\"kubernetes.io/os\": linux'" +} + +# validate tolerations include the builtins when custom ones are provided +deny[msg] { + input.kind == "DaemonSet" + not input.spec.template.spec.tolerations[0] == { "key": "node-role.kubernetes.io/master", "effect": "NoSchedule", "operator": "Exists" } + msg = "controller tolerations does not include node-role.kubernetes.io/master:NoSchedule" +} diff --git a/charts/metallb/templates/NOTES.txt b/charts/metallb/templates/NOTES.txt new file mode 100644 index 00000000..23d1d5bc --- /dev/null +++ b/charts/metallb/templates/NOTES.txt @@ -0,0 +1,4 @@ +MetalLB is now running in the cluster. + +Now you can configure it via its CRs. Please refer to the metallb official docs +on how to use the CRs. diff --git a/charts/metallb/templates/_helpers.tpl b/charts/metallb/templates/_helpers.tpl new file mode 100644 index 00000000..53d9528d --- /dev/null +++ b/charts/metallb/templates/_helpers.tpl @@ -0,0 +1,113 @@ +{{/* 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 }} + +{{/* +Common labels +*/}} +{{- define "metallb.labels" -}} +helm.sh/chart: {{ include "metallb.chart" . }} +{{ include "metallb.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "metallb.selectorLabels" -}} +app.kubernetes.io/name: {{ include "metallb.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the controller service account to use +*/}} +{{- define "metallb.controller.serviceAccountName" -}} +{{- if .Values.controller.serviceAccount.create }} +{{- default (printf "%s-controller" (include "metallb.fullname" .)) .Values.controller.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.controller.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create the name of the speaker service account to use +*/}} +{{- define "metallb.speaker.serviceAccountName" -}} +{{- if .Values.speaker.serviceAccount.create }} +{{- default (printf "%s-speaker" (include "metallb.fullname" .)) .Values.speaker.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.speaker.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create the name of the settings Secret to use. +*/}} +{{- define "metallb.secretName" -}} + {{ default ( printf "%s-memberlist" (include "metallb.fullname" .)) .Values.speaker.secretName | trunc 63 | trimSuffix "-" }} +{{- end -}} + +{{- define "metrics.exposedportname" -}} +{{- if .Values.prometheus.secureMetricsPort -}} +"metricshttps" +{{- else -}} +"metrics" +{{- end -}} +{{- end -}} + +{{- define "metrics.exposedfrrportname" -}} +{{- if .Values.speaker.frr.secureMetricsPort -}} +"frrmetricshttps" +{{- else -}} +"frrmetrics" +{{- end }} +{{- end }} + +{{- define "metrics.exposedport" -}} +{{- if .Values.prometheus.secureMetricsPort -}} +{{ .Values.prometheus.secureMetricsPort }} +{{- else -}} +{{ .Values.prometheus.metricsPort }} +{{- end -}} +{{- end }} + +{{- define "metrics.exposedfrrport" -}} +{{- if .Values.speaker.frr.secureMetricsPort -}} +{{ .Values.speaker.frr.secureMetricsPort }} +{{- else -}} +{{ .Values.speaker.frr.metricsPort }} +{{- end }} +{{- end }} diff --git a/charts/metallb/templates/controller.yaml b/charts/metallb/templates/controller.yaml new file mode 100644 index 00000000..5ba71891 --- /dev/null +++ b/charts/metallb/templates/controller.yaml @@ -0,0 +1,181 @@ +{{- if .Values.controller.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "metallb.fullname" . }}-controller + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: controller + {{- range $key, $value := .Values.controller.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + {{- if .Values.controller.strategy }} + strategy: {{- toYaml .Values.controller.strategy | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "metallb.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: controller + template: + metadata: + {{- if or .Values.prometheus.scrapeAnnotations .Values.controller.podAnnotations }} + annotations: + {{- if .Values.prometheus.scrapeAnnotations }} + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .Values.prometheus.metricsPort }}" + {{- end }} + {{- with .Values.controller.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + labels: + {{- include "metallb.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: controller + {{- range $key, $value := .Values.controller.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + {{- with .Values.controller.runtimeClassName }} + runtimeClassName: {{ . | quote }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ template "metallb.controller.serviceAccountName" . }} + terminationGracePeriodSeconds: 0 +{{- if .Values.controller.securityContext }} + securityContext: +{{ toYaml .Values.controller.securityContext | indent 8 }} +{{- end }} + containers: + - name: controller + image: {{ .Values.controller.image.repository }}:{{ .Values.controller.image.tag | default .Chart.AppVersion }} + {{- if .Values.controller.image.pullPolicy }} + imagePullPolicy: {{ .Values.controller.image.pullPolicy }} + {{- end }} + {{- if .Values.controller.command }} + command: + - {{ .Values.controller.command }} + {{- end }} + args: + - --port={{ .Values.prometheus.metricsPort }} + {{- with .Values.controller.logLevel }} + - --log-level={{ . }} + {{- end }} + - --cert-service-name=metallb-webhook-service + {{- if .Values.loadBalancerClass }} + - --lb-class={{ .Values.loadBalancerClass }} + {{- end }} + {{- if .Values.controller.webhookMode }} + - --webhook-mode={{ .Values.controller.webhookMode }} + {{- end }} + env: + {{- if and .Values.speaker.enabled .Values.speaker.memberlist.enabled }} + - name: METALLB_ML_SECRET_NAME + value: {{ include "metallb.secretName" . }} + - name: METALLB_DEPLOYMENT + value: {{ template "metallb.fullname" . }}-controller + {{- end }} + {{- if .Values.speaker.frr.enabled }} + - name: METALLB_BGP_TYPE + value: frr + {{- end }} + ports: + - name: monitoring + containerPort: {{ .Values.prometheus.metricsPort }} + - containerPort: 9443 + name: webhook-server + protocol: TCP + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + {{- if .Values.controller.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /metrics + port: monitoring + initialDelaySeconds: {{ .Values.controller.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.controller.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.controller.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.controller.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.controller.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.controller.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /metrics + port: monitoring + initialDelaySeconds: {{ .Values.controller.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.controller.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.controller.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.controller.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.controller.readinessProbe.failureThreshold }} + {{- end }} + {{- with .Values.controller.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + {{- if .Values.prometheus.secureMetricsPort }} + - name: kube-rbac-proxy + image: {{ .Values.prometheus.rbacProxy.repository }}:{{ .Values.prometheus.rbacProxy.tag }} + imagePullPolicy: {{ .Values.prometheus.rbacProxy.pullPolicy }} + args: + - --logtostderr + - --secure-listen-address=:{{ .Values.prometheus.secureMetricsPort }} + - --upstream=http://127.0.0.1:{{ .Values.prometheus.metricsPort }}/ + - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + {{- if .Values.prometheus.controllerMetricsTLSSecret }} + - --tls-private-key-file=/etc/metrics/tls.key + - --tls-cert-file=/etc/metrics/tls.crt + {{- end }} + ports: + - containerPort: {{ .Values.prometheus.secureMetricsPort }} + name: metricshttps + resources: + requests: + cpu: 10m + memory: 20Mi + terminationMessagePolicy: FallbackToLogsOnError + {{- if .Values.prometheus.controllerMetricsTLSSecret }} + volumeMounts: + - name: metrics-certs + mountPath: /etc/metrics + readOnly: true + {{- end }} + {{ end }} + nodeSelector: + "kubernetes.io/os": linux + {{- with .Values.controller.nodeSelector }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.controller.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.controller.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.controller.priorityClassName }} + priorityClassName: {{ . | quote }} + {{- end }} + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: webhook-server-cert + {{- if .Values.prometheus.controllerMetricsTLSSecret }} + - name: metrics-certs + secret: + secretName: {{ .Values.prometheus.controllerMetricsTLSSecret }} + {{- end }} +{{- end }} diff --git a/charts/metallb/templates/deprecated_configInline.yaml b/charts/metallb/templates/deprecated_configInline.yaml new file mode 100644 index 00000000..8a1a551c --- /dev/null +++ b/charts/metallb/templates/deprecated_configInline.yaml @@ -0,0 +1,3 @@ +{{- if .Values.configInline }} +{{- fail "Starting from v0.13.0 configInline is no longer supported. Please see https://metallb.universe.tf/#backward-compatibility" }} +{{- end }} diff --git a/charts/metallb/templates/exclude-l2-config.yaml b/charts/metallb/templates/exclude-l2-config.yaml new file mode 100644 index 00000000..7cc2ff34 --- /dev/null +++ b/charts/metallb/templates/exclude-l2-config.yaml @@ -0,0 +1,22 @@ +{{- if .Values.speaker.excludeInterfaces.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: metallb-excludel2 +data: + excludel2.yaml: | + announcedInterfacesToExclude: + - docker.* + - cbr.* + - dummy.* + - virbr.* + - lxcbr.* + - veth.* + - lo + - ^cali.* + - ^tunl.* + - flannel.* + - kube-ipvs.* + - cni.* + - ^nodelocaldns.* +{{- end }} \ No newline at end of file diff --git a/charts/metallb/templates/podmonitor.yaml b/charts/metallb/templates/podmonitor.yaml new file mode 100644 index 00000000..93a7fd69 --- /dev/null +++ b/charts/metallb/templates/podmonitor.yaml @@ -0,0 +1,106 @@ +{{- if .Values.prometheus.podMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: {{ template "metallb.fullname" . }}-controller + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: controller + {{- if .Values.prometheus.podMonitor.additionalLabels }} +{{ toYaml .Values.prometheus.podMonitor.additionalLabels | indent 4 }} + {{- end }} + {{- if .Values.prometheus.podMonitor.annotations }} + annotations: +{{ toYaml .Values.prometheus.podMonitor.annotations | indent 4 }} + {{- end }} +spec: + jobLabel: {{ .Values.prometheus.podMonitor.jobLabel | quote }} + selector: + matchLabels: + {{- include "metallb.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: controller + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + podMetricsEndpoints: + - port: monitoring + path: /metrics + {{- if .Values.prometheus.podMonitor.interval }} + interval: {{ .Values.prometheus.podMonitor.interval }} + {{- end }} +{{- if .Values.prometheus.podMonitor.metricRelabelings }} + metricRelabelings: +{{- toYaml .Values.prometheus.podMonitor.metricRelabelings | nindent 4 }} +{{- end }} +{{- if .Values.prometheus.podMonitor.relabelings }} + relabelings: +{{- toYaml .Values.prometheus.podMonitor.relabelings | nindent 4 }} +{{- end }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: {{ template "metallb.fullname" . }}-speaker + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: speaker + {{- if .Values.prometheus.podMonitor.additionalLabels }} +{{ toYaml .Values.prometheus.podMonitor.additionalLabels | indent 4 }} + {{- end }} + {{- if .Values.prometheus.podMonitor.annotations }} + annotations: +{{ toYaml .Values.prometheus.podMonitor.annotations | indent 4 }} + {{- end }} +spec: + jobLabel: {{ .Values.prometheus.podMonitor.jobLabel | quote }} + selector: + matchLabels: + {{- include "metallb.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: speaker + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + podMetricsEndpoints: + - port: monitoring + path: /metrics + {{- if .Values.prometheus.podMonitor.interval }} + interval: {{ .Values.prometheus.podMonitor.interval }} + {{- end }} +{{- if .Values.prometheus.podMonitor.metricRelabelings }} + metricRelabelings: +{{- toYaml .Values.prometheus.podMonitor.metricRelabelings | nindent 4 }} +{{- end }} +{{- if .Values.prometheus.podMonitor.relabelings }} + relabelings: +{{- toYaml .Values.prometheus.podMonitor.relabelings | nindent 4 }} +{{- end }} +--- +{{- if .Values.prometheus.rbacPrometheus }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "metallb.fullname" . }}-prometheus +rules: + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "metallb.fullname" . }}-prometheus +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "metallb.fullname" . }}-prometheus +subjects: + - kind: ServiceAccount + name: {{ required ".Values.prometheus.serviceAccount must be defined when .Values.prometheus.podMonitor.enabled == true" .Values.prometheus.serviceAccount }} + namespace: {{ required ".Values.prometheus.namespace must be defined when .Values.prometheus.podMonitor.enabled == true" .Values.prometheus.namespace }} +{{- end }} +{{- end }} diff --git a/charts/metallb/templates/prometheusrules.yaml b/charts/metallb/templates/prometheusrules.yaml new file mode 100644 index 00000000..463aacaf --- /dev/null +++ b/charts/metallb/templates/prometheusrules.yaml @@ -0,0 +1,84 @@ +{{- if .Values.prometheus.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ template "metallb.fullname" . }} + labels: + {{- include "metallb.labels" . | nindent 4 }} + {{- if .Values.prometheus.prometheusRule.additionalLabels }} +{{ toYaml .Values.prometheus.prometheusRule.additionalLabels | indent 4 }} + {{- end }} + {{- if .Values.prometheus.prometheusRule.annotations }} + annotations: +{{ toYaml .Values.prometheus.prometheusRule.annotations | indent 4 }} + {{- end }} +spec: + groups: + - name: {{ template "metallb.fullname" . }}.rules + rules: + {{- if .Values.prometheus.prometheusRule.staleConfig.enabled }} + - alert: MetalLBStaleConfig + annotations: + message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod + }} has a stale config for > 1 minute'`}} + expr: metallb_k8s_client_config_stale_bool{job="{{ include "metallb.name" . }}"} == 1 + for: 1m + {{- with .Values.prometheus.prometheusRule.staleConfig.labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.prometheus.prometheusRule.configNotLoaded.enabled }} + - alert: MetalLBConfigNotLoaded + annotations: + message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod + }} has not loaded for > 1 minute'`}} + expr: metallb_k8s_client_config_loaded_bool{job="{{ include "metallb.name" . }}"} == 0 + for: 1m + {{- with .Values.prometheus.prometheusRule.configNotLoaded.labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.prometheus.prometheusRule.addressPoolExhausted.enabled }} + - alert: MetalLBAddressPoolExhausted + annotations: + message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod + }} has exhausted address pool {{ $labels.pool }} for > 1 minute'`}} + expr: metallb_allocator_addresses_in_use_total >= on(pool) metallb_allocator_addresses_total + for: 1m + {{- with .Values.prometheus.prometheusRule.addressPoolExhausted.labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + + {{- if .Values.prometheus.prometheusRule.addressPoolUsage.enabled }} + {{- range .Values.prometheus.prometheusRule.addressPoolUsage.thresholds }} + - alert: MetalLBAddressPoolUsage{{ .percent }}Percent + annotations: + message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod + }} has address pool {{ $labels.pool }} past `}}{{ .percent }}{{`% usage for > 1 minute'`}} + expr: ( metallb_allocator_addresses_in_use_total / on(pool) metallb_allocator_addresses_total ) * 100 > {{ .percent }} + {{- with .labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.prometheus.prometheusRule.bgpSessionDown.enabled }} + - alert: MetalLBBGPSessionDown + annotations: + message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod + }} has BGP session {{ $labels.peer }} down for > 1 minute'`}} + expr: metallb_bgp_session_up{job="{{ include "metallb.name" . }}"} == 0 + for: 1m + {{- with .Values.prometheus.prometheusRule.bgpSessionDown.labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- with .Values.prometheus.prometheusRule.extraAlerts }} + {{- toYaml . | nindent 4 }} + {{- end}} +{{- end }} diff --git a/charts/metallb/templates/rbac.yaml b/charts/metallb/templates/rbac.yaml new file mode 100644 index 00000000..6a38304b --- /dev/null +++ b/charts/metallb/templates/rbac.yaml @@ -0,0 +1,206 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "metallb.fullname" . }}:controller + labels: + {{- include "metallb.labels" . | nindent 4 }} +rules: +- apiGroups: [""] + resources: ["services", "namespaces"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["nodes"] + verbs: ["list"] +- apiGroups: [""] + resources: ["services/status"] + verbs: ["update"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"] + resourceNames: ["metallb-webhook-configuration"] + verbs: ["create", "delete", "get", "list", "patch", "update", "watch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"] + verbs: ["list", "watch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + resourceNames: ["addresspools.metallb.io","bfdprofiles.metallb.io","bgpadvertisements.metallb.io", + "bgppeers.metallb.io","ipaddresspools.metallb.io","l2advertisements.metallb.io","communities.metallb.io"] + verbs: ["create", "delete", "get", "list", "patch", "update", "watch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["list", "watch"] +{{- if .Values.prometheus.secureMetricsPort }} +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] +- apiGroups: ["authorization.k8s.io"] + resources: ["subjectaccessreviews"] + verbs: ["create"] +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "metallb.fullname" . }}:speaker + labels: + {{- include "metallb.labels" . | nindent 4 }} +rules: +- apiGroups: [""] + resources: ["services", "endpoints", "nodes", "namespaces"] + verbs: ["get", "list", "watch"] +- apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] +{{- if .Values.prometheus.secureMetricsPort }} +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] +- apiGroups: ["authorization.k8s.io"] + resources: ["subjectaccessreviews"] + verbs: ["create"] +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "metallb.fullname" . }}-pod-lister + labels: {{- include "metallb.labels" . | nindent 4 }} +rules: +- apiGroups: [""] + resources: ["pods"] + verbs: ["list"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["addresspools"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["bfdprofiles"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["bgppeers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["l2advertisements"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["bgpadvertisements"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["ipaddresspools"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["communities"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "metallb.fullname" . }}-controller + labels: {{- include "metallb.labels" . | nindent 4 }} +rules: +{{- if .Values.speaker.memberlist.enabled }} +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "list", "watch"] +- apiGroups: [""] + resources: ["secrets"] + resourceNames: [{{ include "metallb.secretName" . | quote }}] + verbs: ["list"] +- apiGroups: ["apps"] + resources: ["deployments"] + resourceNames: ["{{ template "metallb.fullname" . }}-controller"] + verbs: ["get"] +{{- end }} +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "delete", "get", "list", "patch", "update", "watch"] +- apiGroups: ["metallb.io"] + resources: ["addresspools"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["ipaddresspools"] + verbs: ["get", "list", "watch"] +- apiGroups: ["metallb.io"] + resources: ["bgppeers"] + verbs: ["get", "list"] +- apiGroups: ["metallb.io"] + resources: ["bgpadvertisements"] + verbs: ["get", "list"] +- apiGroups: ["metallb.io"] + resources: ["l2advertisements"] + verbs: ["get", "list"] +- apiGroups: ["metallb.io"] + resources: ["communities"] + verbs: ["get", "list","watch"] +- apiGroups: ["metallb.io"] + resources: ["bfdprofiles"] + verbs: ["get", "list","watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "metallb.fullname" . }}:controller + labels: + {{- include "metallb.labels" . | nindent 4 }} +subjects: +- kind: ServiceAccount + name: {{ template "metallb.controller.serviceAccountName" . }} + 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: + {{- include "metallb.labels" . | nindent 4 }} +subjects: +- kind: ServiceAccount + name: {{ template "metallb.speaker.serviceAccountName" . }} + 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: {{ include "metallb.fullname" . }}-pod-lister + labels: {{- include "metallb.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "metallb.fullname" . }}-pod-lister +subjects: +- kind: ServiceAccount + name: {{ include "metallb.speaker.serviceAccountName" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "metallb.fullname" . }}-controller + labels: {{- include "metallb.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "metallb.fullname" . }}-controller +subjects: +- kind: ServiceAccount + name: {{ include "metallb.controller.serviceAccountName" . }} +{{- end -}} diff --git a/charts/metallb/templates/service-accounts.yaml b/charts/metallb/templates/service-accounts.yaml new file mode 100644 index 00000000..95609e5e --- /dev/null +++ b/charts/metallb/templates/service-accounts.yaml @@ -0,0 +1,28 @@ +{{- if .Values.controller.serviceAccount.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "metallb.controller.serviceAccountName" . }} + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: controller + {{- with .Values.controller.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +{{- if .Values.speaker.serviceAccount.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "metallb.speaker.serviceAccountName" . }} + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: speaker + {{- with .Values.speaker.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/metallb/templates/servicemonitor.yaml b/charts/metallb/templates/servicemonitor.yaml new file mode 100644 index 00000000..1d8563d2 --- /dev/null +++ b/charts/metallb/templates/servicemonitor.yaml @@ -0,0 +1,188 @@ +{{- if .Values.prometheus.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "metallb.fullname" . }}-speaker-monitor + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: speaker + {{- if .Values.prometheus.serviceMonitor.speaker.additionalLabels }} +{{ toYaml .Values.prometheus.serviceMonitor.speaker.additionalLabels | indent 4 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.speaker.annotations }} + annotations: +{{ toYaml .Values.prometheus.serviceMonitor.speaker.annotations | indent 4 }} + {{- end }} +spec: + endpoints: + - port: {{ template "metrics.exposedportname" . }} + honorLabels: true + {{- if .Values.prometheus.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.prometheus.serviceMonitor.metricRelabelings | nindent 8 }} + {{- end -}} + {{- if .Values.prometheus.serviceMonitor.relabelings }} + relabelings: + {{- toYaml .Values.prometheus.serviceMonitor.relabelings | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.interval }} + interval: {{ .Values.prometheus.serviceMonitor.interval }} + {{- end -}} +{{ if .Values.prometheus.secureMetricsPort }} + bearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token" + scheme: "https" +{{- if .Values.prometheus.serviceMonitor.speaker.tlsConfig }} + tlsConfig: +{{ toYaml .Values.prometheus.serviceMonitor.speaker.tlsConfig | indent 8 }} +{{- end }} +{{ end }} +{{- if .Values.speaker.frr.enabled }} + - port: {{ template "metrics.exposedfrrportname" . }} + honorLabels: true +{{ if .Values.speaker.frr.secureMetricsPort }} + {{- if .Values.prometheus.serviceMonitor.interval }} + interval: {{ .Values.prometheus.serviceMonitor.interval }} + {{- end }} + bearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token" + scheme: "https" +{{- if .Values.prometheus.serviceMonitor.speaker.tlsConfig }} + tlsConfig: +{{ toYaml .Values.prometheus.serviceMonitor.speaker.tlsConfig | indent 8 }} +{{- end }} +{{- end }} +{{- end }} + jobLabel: {{ .Values.prometheus.serviceMonitor.jobLabel | quote }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + name: {{ template "metallb.fullname" . }}-speaker-monitor-service +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/scrape: "true" + {{- if .Values.prometheus.serviceMonitor.speaker.annotations }} +{{ toYaml .Values.prometheus.serviceMonitor.speaker.annotations | indent 4 }} + {{- end }} + labels: + name: {{ template "metallb.fullname" . }}-speaker-monitor-service + name: {{ template "metallb.fullname" . }}-speaker-monitor-service +spec: + selector: + {{- include "metallb.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: speaker + clusterIP: None + ports: + - name: {{ template "metrics.exposedportname" . }} + port: {{ template "metrics.exposedport" . }} + targetPort: {{ template "metrics.exposedport" . }} +{{- if .Values.speaker.frr.enabled }} + - name: {{ template "metrics.exposedfrrportname" . }} + port: {{ template "metrics.exposedfrrport" . }} + targetPort: {{ template "metrics.exposedfrrport" . }} +{{- end }} + sessionAffinity: None + type: ClusterIP +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "metallb.fullname" . }}-controller-monitor + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: speaker + {{- if .Values.prometheus.serviceMonitor.controller.additionalLabels }} +{{ toYaml .Values.prometheus.serviceMonitor.controller.additionalLabels | indent 4 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.controller.annotations }} + annotations: +{{ toYaml .Values.prometheus.serviceMonitor.controller.annotations | indent 4 }} + {{- end }} +spec: + endpoints: + - port: {{ template "metrics.exposedportname" . }} + {{- if .Values.prometheus.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.prometheus.serviceMonitor.metricRelabelings | nindent 8 }} + {{- end -}} + {{- if .Values.prometheus.serviceMonitor.relabelings }} + relabelings: + {{- toYaml .Values.prometheus.serviceMonitor.relabelings | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.interval }} + interval: {{ .Values.prometheus.serviceMonitor.interval }} + {{- end }} + honorLabels: true +{{- if .Values.prometheus.secureMetricsPort }} + bearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token" + scheme: "https" +{{- if .Values.prometheus.serviceMonitor.controller.tlsConfig }} + tlsConfig: +{{ toYaml .Values.prometheus.serviceMonitor.controller.tlsConfig | indent 8 }} +{{- end }} +{{- end }} + jobLabel: {{ .Values.prometheus.serviceMonitor.jobLabel | quote }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + name: {{ template "metallb.fullname" . }}-controller-monitor-service +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/scrape: "true" + {{- if .Values.prometheus.serviceMonitor.controller.annotations }} +{{ toYaml .Values.prometheus.serviceMonitor.controller.annotations | indent 4 }} + {{- end }} + labels: + name: {{ template "metallb.fullname" . }}-controller-monitor-service + name: {{ template "metallb.fullname" . }}-controller-monitor-service +spec: + selector: + {{- include "metallb.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: controller + clusterIP: None + ports: + - name: {{ template "metrics.exposedportname" . }} + port: {{ template "metrics.exposedport" . }} + targetPort: {{ template "metrics.exposedport" . }} + sessionAffinity: None + type: ClusterIP +--- +{{- if .Values.prometheus.rbacPrometheus }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "metallb.fullname" . }}-prometheus +rules: + - apiGroups: + - "" + resources: + - pods + - services + - endpoints + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "metallb.fullname" . }}-prometheus +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "metallb.fullname" . }}-prometheus +subjects: + - kind: ServiceAccount + name: {{ required ".Values.prometheus.serviceAccount must be defined when .Values.prometheus.serviceMonitor.enabled == true" .Values.prometheus.serviceAccount }} + namespace: {{ required ".Values.prometheus.namespace must be defined when .Values.prometheus.serviceMonitor.enabled == true" .Values.prometheus.namespace }} +{{- end }} +{{- end }} diff --git a/charts/metallb/templates/speaker.yaml b/charts/metallb/templates/speaker.yaml new file mode 100644 index 00000000..4bbbfb1d --- /dev/null +++ b/charts/metallb/templates/speaker.yaml @@ -0,0 +1,505 @@ +{{- if .Values.speaker.frr.enabled }} +# FRR expects to have these files owned by frr:frr on startup. +# Having them in a ConfigMap allows us to modify behaviors: for example enabling more daemons on startup. +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "metallb.fullname" . }}-frr-startup + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: speaker +data: + daemons: | + # This file tells the frr package which daemons to start. + # + # Sample configurations for these daemons can be found in + # /usr/share/doc/frr/examples/. + # + # ATTENTION: + # + # When activating a daemon for the first time, a config file, even if it is + # empty, has to be present *and* be owned by the user and group "frr", else + # the daemon will not be started by /etc/init.d/frr. The permissions should + # be u=rw,g=r,o=. + # When using "vtysh" such a config file is also needed. It should be owned by + # group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. + # + # The watchfrr and zebra daemons are always started. + # + bgpd=yes + ospfd=no + ospf6d=no + ripd=no + ripngd=no + isisd=no + pimd=no + ldpd=no + nhrpd=no + eigrpd=no + babeld=no + sharpd=no + pbrd=no + bfdd=yes + fabricd=no + vrrpd=no + + # + # If this option is set the /etc/init.d/frr script automatically loads + # the config via "vtysh -b" when the servers are started. + # Check /etc/pam.d/frr if you intend to use "vtysh"! + # + vtysh_enable=yes + zebra_options=" -A 127.0.0.1 -s 90000000" + bgpd_options=" -A 127.0.0.1 -p 0" + ospfd_options=" -A 127.0.0.1" + ospf6d_options=" -A ::1" + ripd_options=" -A 127.0.0.1" + ripngd_options=" -A ::1" + isisd_options=" -A 127.0.0.1" + pimd_options=" -A 127.0.0.1" + ldpd_options=" -A 127.0.0.1" + nhrpd_options=" -A 127.0.0.1" + eigrpd_options=" -A 127.0.0.1" + babeld_options=" -A 127.0.0.1" + sharpd_options=" -A 127.0.0.1" + pbrd_options=" -A 127.0.0.1" + staticd_options="-A 127.0.0.1" + bfdd_options=" -A 127.0.0.1" + fabricd_options="-A 127.0.0.1" + vrrpd_options=" -A 127.0.0.1" + + # configuration profile + # + #frr_profile="traditional" + #frr_profile="datacenter" + + # + # This is the maximum number of FD's that will be available. + # Upon startup this is read by the control files and ulimit + # is called. Uncomment and use a reasonable value for your + # setup if you are expecting a large number of peers in + # say BGP. + #MAX_FDS=1024 + + # The list of daemons to watch is automatically generated by the init script. + #watchfrr_options="" + + # for debugging purposes, you can specify a "wrap" command to start instead + # of starting the daemon directly, e.g. to use valgrind on ospfd: + # ospfd_wrap="/usr/bin/valgrind" + # or you can use "all_wrap" for all daemons, e.g. to use perf record: + # all_wrap="/usr/bin/perf record --call-graph -" + # the normal daemon command is added to this at the end. + vtysh.conf: |+ + service integrated-vtysh-config + frr.conf: |+ + ! This file gets overriden the first time the speaker renders a config. + ! So anything configured here is only temporary. + frr version 7.5.1 + frr defaults traditional + hostname Router + line vty + log file /etc/frr/frr.log informational +{{- end }} +--- +{{- if .Values.speaker.enabled }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ template "metallb.fullname" . }}-speaker + labels: + {{- include "metallb.labels" . | nindent 4 }} + app.kubernetes.io/component: speaker + {{- range $key, $value := .Values.speaker.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + {{- if .Values.speaker.updateStrategy }} + updateStrategy: {{- toYaml .Values.speaker.updateStrategy | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "metallb.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: speaker + template: + metadata: + {{- if or .Values.prometheus.scrapeAnnotations .Values.speaker.podAnnotations }} + annotations: + {{- if .Values.prometheus.scrapeAnnotations }} + prometheus.io/scrape: "true" + {{- if not .Values.speaker.frr.enabled }} + prometheus.io/port: "{{ .Values.prometheus.metricsPort }}" + {{- end }} + {{- end }} + {{- with .Values.speaker.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + labels: + {{- include "metallb.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: speaker + {{- range $key, $value := .Values.speaker.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + {{- if .Values.speaker.runtimeClassName }} + runtimeClassName: {{ .Values.speaker.runtimeClassName }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ template "metallb.speaker.serviceAccountName" . }} + terminationGracePeriodSeconds: 0 + hostNetwork: true + volumes: + {{- if .Values.speaker.memberlist.enabled }} + - name: memberlist + secret: + secretName: {{ include "metallb.secretName" . }} + defaultMode: 420 + {{- end }} + {{- if .Values.speaker.excludeInterfaces.enabled }} + - name: metallb-excludel2 + configMap: + defaultMode: 256 + name: metallb-excludel2 + {{- end }} + {{- if .Values.speaker.frr.enabled }} + - name: frr-sockets + emptyDir: {} + - name: frr-startup + configMap: + name: {{ template "metallb.fullname" . }}-frr-startup + - name: frr-conf + emptyDir: {} + - name: reloader + emptyDir: {} + - name: metrics + emptyDir: {} + {{- if .Values.prometheus.speakerMetricsTLSSecret }} + - name: metrics-certs + secret: + secretName: {{ .Values.prometheus.speakerMetricsTLSSecret }} + {{- end }} + initContainers: + # Copies the initial config files with the right permissions to the shared volume. + - name: cp-frr-files + image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }} + securityContext: + runAsUser: 100 + runAsGroup: 101 + command: ["/bin/sh", "-c", "cp -rLf /tmp/frr/* /etc/frr/"] + volumeMounts: + - name: frr-startup + mountPath: /tmp/frr + - name: frr-conf + mountPath: /etc/frr + # Copies the reloader to the shared volume between the speaker and reloader. + - name: cp-reloader + image: {{ .Values.speaker.image.repository }}:{{ .Values.speaker.image.tag | default .Chart.AppVersion }} + command: ["/bin/sh", "-c", "cp -f /frr-reloader.sh /etc/frr_reloader/"] + volumeMounts: + - name: reloader + mountPath: /etc/frr_reloader + # Copies the metrics exporter + - name: cp-metrics + image: {{ .Values.speaker.image.repository }}:{{ .Values.speaker.image.tag | default .Chart.AppVersion }} + command: ["/bin/sh", "-c", "cp -f /frr-metrics /etc/frr_metrics/"] + volumeMounts: + - name: metrics + mountPath: /etc/frr_metrics + shareProcessNamespace: true + {{- end }} + containers: + - name: speaker + image: {{ .Values.speaker.image.repository }}:{{ .Values.speaker.image.tag | default .Chart.AppVersion }} + {{- if .Values.speaker.image.pullPolicy }} + imagePullPolicy: {{ .Values.speaker.image.pullPolicy }} + {{- end }} + {{- if .Values.speaker.command }} + command: + - {{ .Values.speaker.command }} + {{- end }} + args: + - --port={{ .Values.prometheus.metricsPort }} + {{- with .Values.speaker.logLevel }} + - --log-level={{ . }} + {{- end }} + {{- if .Values.loadBalancerClass }} + - --lb-class={{ .Values.loadBalancerClass }} + {{- end }} + env: + - name: METALLB_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: METALLB_HOST + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.speaker.memberlist.enabled }} + - name: METALLB_ML_BIND_ADDR + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: METALLB_ML_LABELS + value: "app.kubernetes.io/name={{ include "metallb.name" . }},app.kubernetes.io/component=speaker" + - name: METALLB_ML_BIND_PORT + value: "{{ .Values.speaker.memberlist.mlBindPort }}" + - name: METALLB_ML_SECRET_KEY_PATH + value: "{{ .Values.speaker.memberlist.mlSecretKeyPath }}" + {{- end }} + {{- if .Values.speaker.frr.enabled }} + - name: FRR_CONFIG_FILE + value: /etc/frr_reloader/frr.conf + - name: FRR_RELOADER_PID_FILE + value: /etc/frr_reloader/reloader.pid + - name: METALLB_BGP_TYPE + value: frr + {{- end }} + ports: + - name: monitoring + containerPort: {{ .Values.prometheus.metricsPort }} + {{- if .Values.speaker.memberlist.enabled }} + - name: memberlist-tcp + containerPort: {{ .Values.speaker.memberlist.mlBindPort }} + protocol: TCP + - name: memberlist-udp + containerPort: {{ .Values.speaker.memberlist.mlBindPort }} + protocol: UDP + {{- end }} + {{- if .Values.speaker.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /metrics + port: monitoring + initialDelaySeconds: {{ .Values.speaker.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.speaker.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.speaker.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.speaker.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.speaker.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.speaker.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /metrics + port: monitoring + initialDelaySeconds: {{ .Values.speaker.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.speaker.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.speaker.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.speaker.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.speaker.readinessProbe.failureThreshold }} + {{- end }} + {{- with .Values.speaker.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + add: + - NET_RAW + {{- if or .Values.speaker.frr.enabled .Values.speaker.memberlist.enabled .Values.speaker.excludeInterfaces.enabled }} + volumeMounts: + {{- if .Values.speaker.memberlist.enabled }} + - name: memberlist + mountPath: {{ .Values.speaker.memberlist.mlSecretKeyPath }} + {{- end }} + {{- if .Values.speaker.frr.enabled }} + - name: reloader + mountPath: /etc/frr_reloader + {{- end }} + {{- if .Values.speaker.excludeInterfaces.enabled }} + - name: metallb-excludel2 + mountPath: /etc/metallb + {{- end }} + {{- end }} + {{- if .Values.speaker.frr.enabled }} + - name: frr + securityContext: + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_ADMIN + - NET_BIND_SERVICE + image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }} + {{- if .Values.speaker.frr.image.pullPolicy }} + imagePullPolicy: {{ .Values.speaker.frr.image.pullPolicy }} + {{- end }} + env: + - name: TINI_SUBREAPER + value: "true" + volumeMounts: + - name: frr-sockets + mountPath: /var/run/frr + - name: frr-conf + mountPath: /etc/frr + # The command is FRR's default entrypoint & waiting for the log file to appear and tailing it. + # If the log file isn't created in 60 seconds the tail fails and the container is restarted. + # This workaround is needed to have the frr logs as part of kubectl logs -c frr < speaker_pod_name >. + command: + - /bin/sh + - -c + - | + /sbin/tini -- /usr/lib/frr/docker-start & + attempts=0 + until [[ -f /etc/frr/frr.log || $attempts -eq 60 ]]; do + sleep 1 + attempts=$(( $attempts + 1 )) + done + tail -f /etc/frr/frr.log + {{- with .Values.speaker.frr.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.speaker.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /livez + port: {{ .Values.speaker.frr.metricsPort }} + periodSeconds: {{ .Values.speaker.livenessProbe.periodSeconds }} + failureThreshold: {{ .Values.speaker.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.speaker.startupProbe.enabled }} + startupProbe: + httpGet: + path: /livez + port: {{ .Values.speaker.frr.metricsPort }} + failureThreshold: {{ .Values.speaker.startupProbe.failureThreshold }} + periodSeconds: {{ .Values.speaker.startupProbe.periodSeconds }} + {{- end }} + - name: reloader + image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }} + {{- if .Values.speaker.frr.image.pullPolicy }} + imagePullPolicy: {{ .Values.speaker.frr.image.pullPolicy }} + {{- end }} + command: ["/etc/frr_reloader/frr-reloader.sh"] + volumeMounts: + - name: frr-sockets + mountPath: /var/run/frr + - name: frr-conf + mountPath: /etc/frr + - name: reloader + mountPath: /etc/frr_reloader + {{- with .Values.speaker.reloader.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + - name: frr-metrics + image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }} + command: ["/etc/frr_metrics/frr-metrics"] + args: + - --metrics-port={{ .Values.speaker.frr.metricsPort }} + ports: + - containerPort: {{ .Values.speaker.frr.metricsPort }} + name: monitoring + volumeMounts: + - name: frr-sockets + mountPath: /var/run/frr + - name: frr-conf + mountPath: /etc/frr + - name: metrics + mountPath: /etc/frr_metrics + {{- with .Values.speaker.frrMetrics.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.prometheus.secureMetricsPort }} + - name: kube-rbac-proxy + image: {{ .Values.prometheus.rbacProxy.repository }}:{{ .Values.prometheus.rbacProxy.tag }} + imagePullPolicy: {{ .Values.prometheus.rbacProxy.pullPolicy }} + args: + - --logtostderr + - --secure-listen-address=:{{ .Values.prometheus.secureMetricsPort }} + - --upstream=http://$(METALLB_HOST):{{ .Values.prometheus.metricsPort }}/ + - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + {{- if .Values.prometheus.speakerMetricsTLSSecret }} + - --tls-private-key-file=/etc/metrics/tls.key + - --tls-cert-file=/etc/metrics/tls.crt + {{- end }} + ports: + - containerPort: {{ .Values.prometheus.secureMetricsPort }} + name: metricshttps + env: + - name: METALLB_HOST + valueFrom: + fieldRef: + fieldPath: status.hostIP + resources: + requests: + cpu: 10m + memory: 20Mi + terminationMessagePolicy: FallbackToLogsOnError + {{- if .Values.prometheus.speakerMetricsTLSSecret }} + volumeMounts: + - name: metrics-certs + mountPath: /etc/metrics + readOnly: true + {{- end }} + {{ end }} + {{- if .Values.speaker.frr.secureMetricsPort }} + - name: kube-rbac-proxy-frr + image: {{ .Values.prometheus.rbacProxy.repository }}:{{ .Values.prometheus.rbacProxy.tag | default .Chart.AppVersion }} + imagePullPolicy: {{ .Values.prometheus.rbacProxy.pullPolicy }} + args: + - --logtostderr + - --secure-listen-address=:{{ .Values.speaker.frr.secureMetricsPort }} + - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + - --upstream=http://$(METALLB_HOST):{{ .Values.speaker.frr.metricsPort }}/ + {{- if .Values.prometheus.speakerMetricsTLSSecret }} + - --tls-private-key-file=/etc/metrics/tls.key + - --tls-cert-file=/etc/metrics/tls.crt + {{- end }} + ports: + - containerPort: {{ .Values.speaker.frr.secureMetricsPort }} + name: metricshttps + env: + - name: METALLB_HOST + valueFrom: + fieldRef: + fieldPath: status.hostIP + resources: + requests: + cpu: 10m + memory: 20Mi + terminationMessagePolicy: FallbackToLogsOnError + {{- if .Values.prometheus.speakerMetricsTLSSecret }} + volumeMounts: + - name: metrics-certs + mountPath: /etc/metrics + readOnly: true + {{- end }} + {{ end }} + nodeSelector: + "kubernetes.io/os": linux + {{- with .Values.speaker.nodeSelector }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.speaker.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or .Values.speaker.tolerateMaster .Values.speaker.tolerations }} + tolerations: + {{- if .Values.speaker.tolerateMaster }} + - key: node-role.kubernetes.io/master + effect: NoSchedule + operator: Exists + - key: node-role.kubernetes.io/control-plane + effect: NoSchedule + operator: Exists + {{- end }} + {{- with .Values.speaker.tolerations }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- end }} + {{- with .Values.speaker.priorityClassName }} + priorityClassName: {{ . | quote }} + {{- end }} +{{- end }} diff --git a/charts/metallb/templates/webhooks.yaml b/charts/metallb/templates/webhooks.yaml new file mode 100644 index 00000000..3f3d5ed7 --- /dev/null +++ b/charts/metallb/templates/webhooks.yaml @@ -0,0 +1,168 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: metallb-webhook-configuration + labels: + {{- include "metallb.labels" . | nindent 4 }} +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta1-addresspool + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: addresspoolvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - addresspools + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta2-bgppeer + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: bgppeervalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta2 + operations: + - CREATE + - UPDATE + resources: + - bgppeers + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta1-ipaddresspool + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: ipaddresspoolvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - ipaddresspools + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta1-bgpadvertisement + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: bgpadvertisementvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - bgpadvertisements + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta1-community + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: communityvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - communities + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta1-bfdprofile + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: bfdprofilevalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - DELETE + resources: + - bfdprofiles + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: metallb-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-metallb-io-v1beta1-l2advertisement + failurePolicy: {{ .Values.crds.validationFailurePolicy }} + name: l2advertisementvalidationwebhook.metallb.io + rules: + - apiGroups: + - metallb.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - l2advertisements + sideEffects: None +--- +apiVersion: v1 +kind: Service +metadata: + name: metallb-webhook-service + labels: + {{- include "metallb.labels" . | nindent 4 }} +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + {{- include "metallb.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: controller +--- +apiVersion: v1 +kind: Secret +metadata: + name: webhook-server-cert + labels: + {{- include "metallb.labels" . | nindent 4 }} diff --git a/charts/metallb/values.schema.json b/charts/metallb/values.schema.json new file mode 100644 index 00000000..5a92e56a --- /dev/null +++ b/charts/metallb/values.schema.json @@ -0,0 +1,427 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "title": "Values", + "type": "object", + "definitions": { + "prometheusAlert": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "labels": { + "type": "object", + "additionalProperties": { "type": "string" } + } + }, + "required": [ "enabled" ] + }, + "probe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "failureThreshold": { + "type": "integer" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + }, + "successThreshold": { + "type": "integer" + }, + "timeoutSeconds": { + "type": "integer" + } + }, + "required": [ + "failureThreshold", + "initialDelaySeconds", + "periodSeconds", + "successThreshold", + "timeoutSeconds" + ] + }, + "component": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "logLevel": { + "type": "string", + "enum": [ "all", "debug", "info", "warn", "error", "none" ] + }, + "image": { + "type": "object", + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "anyOf": [ + { "type": "string" }, + { "type": "null" } + ] + }, + "pullPolicy": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "string", + "enum": [ "Always", "IfNotPresent", "Never" ] + } + ] + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "annotations": { + "type": "object" + } + } + }, + "resources": { + "type": "object" + }, + "nodeSelector": { + "type": "object" + }, + "tolerations": { + "type": "array", + "items": { + "type": "object" + } + }, + "priorityClassName": { + "type":"string" + }, + "runtimeClassName": { + "type":"string" + }, + "affinity": { + "type": "object" + }, + "podAnnotations": { + "type": "object" + }, + "livenessProbe": { + "$ref": "#/definitions/probe" + }, + "readinessProbe": { + "$ref": "#/definitions/probe" + } + }, + "required": [ + "image", + "serviceAccount" + ] + } + }, + "properties": { + "imagePullSecrets": { + "description": "Secrets used for pulling images", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": [ "name" ], + "additionalProperties": false + } + }, + "nameOverride": { + "description": "Override chart name", + "type": "string" + }, + "fullNameOverride": { + "description": "Override fully qualified app name", + "type": "string" + }, + "configInLine": { + "description": "MetalLB configuration", + "type": "object" + }, + "loadBalancerClass": { + "type":"string" + }, + "rbac": { + "description": "RBAC configuration", + "type": "object", + "properties": { + "create": { + "description": "Enable RBAC", + "type": "boolean" + } + } + }, + "prometheus": { + "description": "Prometheus monitoring config", + "type": "object", + "properties": { + "scrapeAnnotations": { "type": "boolean" }, + "metricsPort": { "type": "integer" }, + "secureMetricsPort": { "type": "integer" }, + "rbacPrometheus": { "type": "boolean" }, + "serviceAccount": { "type": "string" }, + "namespace": { "type": "string" }, + "rbacProxy": { + "description": "kube-rbac-proxy configuration", + "type": "object", + "properties": { + "repository": { "type": "string" }, + "tag": { "type": "string" } + } + }, + "podMonitor": { + "description": "Prometheus Operator PodMonitors", + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "additionalMonitors": { "type": "object" }, + "jobLabel": { "type": "string" }, + "interval": { + "anyOf": [ + { "type": "integer" }, + { "type": "null" } + ] + }, + "metricRelabelings": { + "type": "array", + "items": { + "type": "object" + } + }, + "relabelings": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "serviceMonitor": { + "description": "Prometheus Operator ServiceMonitors", + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "jobLabel": { "type": "string" }, + "interval": { + "anyOf": [ + { "type": "integer" }, + { "type": "null" } + ] + }, + "metricRelabelings": { + "type": "array", + "items": { + "type": "object" + } + }, + "relabelings": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "prometheusRule": { + "description": "Prometheus Operator alertmanager alerts", + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "additionalMonitors": { "type": "object" }, + "staleConfig": { "$ref": "#/definitions/prometheusAlert" }, + "configNotLoaded": { "$ref": "#/definitions/prometheusAlert" }, + "addressPoolExhausted": { "$ref": "#/definitions/prometheusAlert" }, + "addressPoolUsage": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "thresholds": { + "type": "array", + "items": { + "type": "object", + "properties": { + "percent": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "labels": { + "type": "object", + "additionalProperties": { "type": "string" } + } + }, + "required": [ "percent" ] + } + } + }, + "required": [ "enabled" ] + }, + "bgpSessionDown": { "$ref": "#/definitions/prometheusAlert" }, + "extraAlerts": { + "type": "array", + "items": { + "type": "object" + } + } + }, + "required": [ + "enabled", + "staleConfig", + "configNotLoaded", + "addressPoolExhausted", + "addressPoolUsage", + "bgpSessionDown" + ] + } + }, + "required": [ "podMonitor", "prometheusRule" ] + }, + "speaker": { + "allOf": [ + { "$ref": "#/definitions/component" }, + { "description": "MetalLB Speaker", + "type": "object", + "properties": { + "tolerateMaster": { + "type": "boolean" + }, + "memberlist": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "mlBindPort": { + "type": "integer" + }, + "mlSecretKeyPath": { + "type": "string" + } + } + }, + "excludeInterfaces": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + }, + "updateStrategy": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ "type" ] + }, + "runtimeClassName": { + "type": "string" + }, + "secretName": { + "type": "string" + }, + "frr": { + "description": "Install FRR container in speaker deployment", + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "image": { "$ref": "#/definitions/component/properties/image" }, + "metricsPort": { "type": "integer" }, + "secureMetricsPort": { "type": "integer" }, + "resources:": { "type": "object" } + }, + "required": [ "enabled" ] + }, + "command" : { + "type": "string" + }, + "reloader": { + "type": "object", + "properties": { + "resources": { "type": "object" } + } + }, + "frrMetrics": { + "type": "object", + "properties": { + "resources": { "type": "object" } + } + } + }, + "required": [ "tolerateMaster" ] + } + ] + }, + "crds": { + "description": "CRD configuration", + "type": "object", + "properties": { + "enabled": { + "description": "Enable CRDs", + "type": "boolean" + }, + "validationFailurePolicy": { + "description": "Failure policy to use with validating webhooks", + "type": "string", + "enum": [ "Ignore", "Fail" ] + } + } + } + }, + "controller": { + "allOf": [ + { "$ref": "#/definitions/component" }, + { "description": "MetalLB Controller", + "type": "object", + "properties": { + "strategy": { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ "type" ] + }, + "command" : { + "type": "string" + }, + "webhookMode" : { + "type": "string" + } + } + } + ] + }, + "required": [ + "controller", + "speaker" + ] +} diff --git a/charts/metallb/values.yaml b/charts/metallb/values.yaml new file mode 100644 index 00000000..4e6b07bf --- /dev/null +++ b/charts/metallb/values.yaml @@ -0,0 +1,342 @@ +# Default values for metallb. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" +loadBalancerClass: "" + +# To configure MetalLB, you must specify ONE of the following two +# options. + +rbac: + # create specifies whether to install and use RBAC rules. + 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 + + # port both controller and speaker will listen on for metrics + metricsPort: 7472 + + # if set, enables rbac proxy on the controller and speaker to expose + # the metrics via tls. + # secureMetricsPort: 9120 + + # the name of the secret to be mounted in the speaker pod + # to expose the metrics securely. If not present, a self signed + # certificate to be used. + speakerMetricsTLSSecret: "" + + # the name of the secret to be mounted in the controller pod + # to expose the metrics securely. If not present, a self signed + # certificate to be used. + controllerMetricsTLSSecret: "" + + # prometheus doens't have the permission to scrape all namespaces so we give it permission to scrape metallb's one + rbacPrometheus: true + + # the service account used by prometheus + # required when " .Values.prometheus.rbacPrometheus == true " and " .Values.prometheus.podMonitor.enabled=true or prometheus.serviceMonitor.enabled=true " + serviceAccount: "" + + # the namespace where prometheus is deployed + # required when " .Values.prometheus.rbacPrometheus == true " and " .Values.prometheus.podMonitor.enabled=true or prometheus.serviceMonitor.enabled=true " + namespace: "" + + # the image to be used for the kuberbacproxy container + rbacProxy: + repository: "registry.opensuse.org/home/kzhelyazkov/metallb-images/containerfile/suse/kube-rbac-proxy" + tag: "v0.14.2" + pullPolicy: IfNotPresent + + # Prometheus Operator PodMonitors + podMonitor: + # enable support for Prometheus Operator + enabled: false + + # optional additionnal labels for podMonitors + additionalLabels: {} + + # optional annotations for podMonitors + annotations: {} + + # Job label for scrape target + jobLabel: "app.kubernetes.io/name" + + # 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 ServiceMonitors. To be used as an alternative + # to podMonitor, supports secure metrics. + serviceMonitor: + # enable support for Prometheus Operator + enabled: false + + speaker: + # optional additional labels for the speaker serviceMonitor + additionalLabels: {} + # optional additional annotations for the speaker serviceMonitor + annotations: {} + # optional tls configuration for the speaker serviceMonitor, in case + # secure metrics are enabled. + tlsConfig: + insecureSkipVerify: true + + controller: + # optional additional labels for the controller serviceMonitor + additionalLabels: {} + # optional additional annotations for the controller serviceMonitor + annotations: {} + # optional tls configuration for the controller serviceMonitor, in case + # secure metrics are enabled. + tlsConfig: + insecureSkipVerify: true + + # Job label for scrape target + jobLabel: "app.kubernetes.io/name" + + # 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 + + # optional additionnal labels for prometheusRules + additionalLabels: {} + + # optional annotations for prometheusRules + annotations: {} + + # MetalLBStaleConfig + staleConfig: + enabled: true + labels: + severity: warning + + # MetalLBConfigNotLoaded + configNotLoaded: + enabled: true + labels: + severity: warning + + # MetalLBAddressPoolExhausted + addressPoolExhausted: + enabled: true + labels: + severity: alert + + addressPoolUsage: + enabled: true + thresholds: + - percent: 75 + labels: + severity: warning + - percent: 85 + labels: + severity: warning + - percent: 95 + labels: + severity: alert + + # MetalLBBGPSessionDown + bgpSessionDown: + enabled: true + labels: + severity: alert + + extraAlerts: [] + +# controller contains configuration specific to the MetalLB cluster +# controller. +controller: + enabled: true + # -- Controller log level. Must be one of: `all`, `debug`, `info`, `warn`, `error` or `none` + logLevel: info + # command: /controller + # webhookMode: enabled + image: + repository: "registry.opensuse.org/home/kzhelyazkov/metallb-images/containerfile/suse/metallb-controller" + tag: "v0.13.10" + pullPolicy: IfNotPresent + ## @param controller.updateStrategy.type Metallb controller deployment strategy type. + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy + ## e.g: + ## strategy: + ## type: RollingUpdate + ## rollingUpdate: + ## maxSurge: 25% + ## maxUnavailable: 25% + ## + strategy: + type: RollingUpdate + serviceAccount: + # 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: "" + annotations: {} + securityContext: + runAsNonRoot: true + # nobody + runAsUser: 65534 + fsGroup: 65534 + resources: {} + # limits: + # cpu: 100m + # memory: 100Mi + nodeSelector: {} + tolerations: [] + priorityClassName: "" + runtimeClassName: "" + affinity: {} + podAnnotations: {} + labels: {} + livenessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + +# speaker contains configuration specific to the MetalLB speaker +# daemonset. +speaker: + enabled: true + # command: /speaker + # -- Speaker log level. Must be one of: `all`, `debug`, `info`, `warn`, `error` or `none` + logLevel: info + tolerateMaster: true + memberlist: + enabled: true + mlBindPort: 7946 + mlSecretKeyPath: "/etc/ml_secret_key" + excludeInterfaces: + enabled: true + image: + repository: "registry.opensuse.org/home/kzhelyazkov/metallb-images/containerfile/suse/metallb-speaker" + tag: "v0.13.10" + pullPolicy: IfNotPresent + ## @param speaker.updateStrategy.type Speaker daemonset strategy type + ## ref: https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/ + ## + updateStrategy: + ## StrategyType + ## Can be set to RollingUpdate or OnDelete + ## + type: RollingUpdate + serviceAccount: + # 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: "" + annotations: {} + ## Defines a secret name for the controller to generate a memberlist encryption secret + ## By default secretName: {{ "metallb.fullname" }}-memberlist + ## + # secretName: + resources: {} + # limits: + # cpu: 100m + # memory: 100Mi + nodeSelector: {} + tolerations: [] + priorityClassName: "" + affinity: {} + ## Selects which runtime class will be used by the pod. + runtimeClassName: "" + podAnnotations: {} + labels: {} + livenessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + readinessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + startupProbe: + enabled: true + failureThreshold: 30 + periodSeconds: 5 + # frr contains configuration specific to the MetalLB FRR container, + # for speaker running alongside FRR. + frr: + enabled: true + image: + repository: "registry.opensuse.org/home/kzhelyazkov/metallb-images/containerfile/suse/frr" + tag: "8.4" + pullPolicy: IfNotPresent + metricsPort: 7473 + resources: {} + + # if set, enables a rbac proxy sidecar container on the speaker to + # expose the frr metrics via tls. + # secureMetricsPort: 9121 + + reloader: + resources: {} + + frrMetrics: + resources: {} + +crds: + enabled: true + validationFailurePolicy: Fail diff --git a/index.html b/index.html index 001c001f..76721945 100755 --- a/index.html +++ b/index.html @@ -221,6 +221,28 @@

Charts

+ +
+ +
+ +
+
+

+ metallb + (0.13.10@v0.13.10) + + github link + +

+

+ A network load-balancer implementation for Kubernetes using standard routing protocols +

+
+ +
+ + Generated on: diff --git a/index.yaml b/index.yaml index b3a76da3..b17c79ad 100755 --- a/index.yaml +++ b/index.yaml @@ -66,6 +66,28 @@ entries: urls: - assets/metal3-deploy/metal3-deploy-0.1.0.tgz version: 0.1.0 + metallb: + - apiVersion: v2 + appVersion: v0.13.10 + created: "2023-08-10T13:47:07.109173+03:00" + dependencies: + - condition: crds.enabled + name: crds + repository: "" + version: 0.13.10 + description: A network load-balancer implementation for Kubernetes using standard + routing protocols + digest: 98066de601d7f6feb44707c6e0d57156d2fe90611a2014dc79f33435a9abb740 + home: https://metallb.universe.tf + icon: https://raw.githubusercontent.com/metallb/metallb/main/website/static/images/logo/metallb-blue-with-name.svg + kubeVersion: '>= 1.19.0-0' + name: metallb + sources: + - https://github.com/metallb/metallb + type: application + urls: + - assets/metallb/metallb-0.13.10.tgz + version: 0.13.10 kubevirt-dashboard-extension: - annotations: catalog.cattle.io/certified: rancher