local defaults = { local defaults = self, // Convention: Top-level fields related to CRDs are public, other fields are hidden // If there is no CRD for the component, everything is hidden in defaults. name:: error 'must provide name', namespace:: error 'must provide namespace', version: error 'must provide version', image: error 'must provide image', resources: { requests: { memory: '400Mi' }, }, //TODO(paulfantom): remove alertmanagerName after release-0.10 and convert to plain 'alerting' object. alertmanagerName:: '', alerting: {}, namespaces:: ['default', 'kube-system', defaults.namespace], replicas: 2, externalLabels: {}, enableFeatures: [], ruleSelector: {}, commonLabels:: { 'app.kubernetes.io/name': 'prometheus', 'app.kubernetes.io/instance': defaults.name, 'app.kubernetes.io/version': defaults.version, 'app.kubernetes.io/component': 'prometheus', 'app.kubernetes.io/part-of': 'kube-prometheus', }, selectorLabels:: { [labelName]: defaults.commonLabels[labelName] for labelName in std.objectFields(defaults.commonLabels) if !std.setMember(labelName, ['app.kubernetes.io/version']) }, mixin:: { ruleLabels: {}, _config: { prometheusSelector: 'job="prometheus-' + defaults.name + '",namespace="' + defaults.namespace + '"', prometheusName: '{{$labels.namespace}}/{{$labels.pod}}', // TODO: remove `thanosSelector` after 0.10.0 release. thanosSelector: 'job="thanos-sidecar"', thanos: { targetGroups: { namespace: defaults.namespace, }, sidecar: { selector: defaults.mixin._config.thanosSelector, thanosPrometheusCommonDimensions: 'namespace, pod', }, }, runbookURLPattern: 'https://runbooks.prometheus-operator.dev/runbooks/prometheus/%s', }, }, thanos: null, reloaderPort:: 8080, }; function(params) { local p = self, _config:: defaults + params, // Safety check assert std.isObject(p._config.resources), assert std.isObject(p._config.mixin._config), _metadata:: { name: 'prometheus-' + p._config.name, namespace: p._config.namespace, labels: p._config.commonLabels, }, mixin:: (import 'github.com/prometheus/prometheus/documentation/prometheus-mixin/mixin.libsonnet') + (import 'github.com/kubernetes-monitoring/kubernetes-mixin/lib/add-runbook-links.libsonnet') + { _config+:: p._config.mixin._config, }, mixinThanos:: (import 'github.com/thanos-io/thanos/mixin/alerts/sidecar.libsonnet') + (import 'github.com/kubernetes-monitoring/kubernetes-mixin/lib/add-runbook-links.libsonnet') + { _config+:: p._config.mixin._config, targetGroups+: p._config.mixin._config.thanos.targetGroups, // TODO: remove `_config.thanosSelector` after 0.10.0 release. sidecar+: { selector: p._config.mixin._config.thanosSelector } + p._config.mixin._config.thanos.sidecar, }, prometheusRule: { apiVersion: 'monitoring.coreos.com/v1', kind: 'PrometheusRule', metadata: p._metadata { labels+: p._config.mixin.ruleLabels, name: p._metadata.name + '-prometheus-rules', }, spec: { local r = if std.objectHasAll(p.mixin, 'prometheusRules') then p.mixin.prometheusRules.groups else [], local a = if std.objectHasAll(p.mixin, 'prometheusAlerts') then p.mixin.prometheusAlerts.groups else [], groups: a + r, }, }, networkPolicy: { apiVersion: 'networking.k8s.io/v1', kind: 'NetworkPolicy', metadata: p.service.metadata, spec: { podSelector: { matchLabels: p._config.selectorLabels, }, policyTypes: ['Egress', 'Ingress'], egress: [{}], ingress: [{ from: [{ podSelector: { matchLabels: { 'app.kubernetes.io/name': 'prometheus', }, }, }], ports: std.map(function(o) { port: o.port, protocol: 'TCP', }, p.service.spec.ports), }, { from: [{ podSelector: { matchLabels: { 'app.kubernetes.io/name': 'prometheus-adapter', }, }, }], ports: [{ port: 9090, protocol: 'TCP', }], }, { from: [{ podSelector: { matchLabels: { 'app.kubernetes.io/name': 'grafana', }, }, }], ports: [{ port: 9090, protocol: 'TCP', }], }] + (if p._config.thanos != null then [{ from: [{ podSelector: { matchLabels: { 'app.kubernetes.io/name': 'thanos-query', }, }, }], ports: [{ port: 10901, protocol: 'TCP', }], }] else []), }, }, serviceAccount: { apiVersion: 'v1', kind: 'ServiceAccount', metadata: p._metadata, automountServiceAccountToken: true, }, service: { apiVersion: 'v1', kind: 'Service', metadata: p._metadata, spec: { ports: [ { name: 'web', targetPort: 'web', port: 9090 }, { name: 'reloader-web', port: p._config.reloaderPort, targetPort: 'reloader-web' }, ] + ( if p._config.thanos != null then [{ name: 'grpc', port: 10901, targetPort: 10901 }] else [] ), selector: p._config.selectorLabels, sessionAffinity: 'ClientIP', }, }, roleBindingSpecificNamespaces: local newSpecificRoleBinding(namespace) = { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'RoleBinding', metadata: p._metadata { namespace: namespace, }, roleRef: { apiGroup: 'rbac.authorization.k8s.io', kind: 'Role', name: p._metadata.name, }, subjects: [{ kind: 'ServiceAccount', name: p.serviceAccount.metadata.name, namespace: p._config.namespace, }], }; { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'RoleBindingList', items: [newSpecificRoleBinding(x) for x in p._config.namespaces], }, clusterRole: { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'ClusterRole', metadata: p._metadata { namespace:: null, }, rules: [ { apiGroups: [''], resources: ['nodes/metrics'], verbs: ['get'], }, { nonResourceURLs: ['/metrics'], verbs: ['get'], }, ], }, roleConfig: { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'Role', metadata: p._metadata { name: p._metadata.name + '-config', }, rules: [{ apiGroups: [''], resources: ['configmaps'], verbs: ['get'], }], }, roleBindingConfig: { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'RoleBinding', metadata: p._metadata { name: p._metadata.name + '-config', }, roleRef: { apiGroup: 'rbac.authorization.k8s.io', kind: 'Role', name: p._metadata.name + '-config', }, subjects: [{ kind: 'ServiceAccount', name: p._metadata.name, namespace: p._config.namespace, }], }, clusterRoleBinding: { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'ClusterRoleBinding', metadata: p._metadata { namespace:: null, }, roleRef: { apiGroup: 'rbac.authorization.k8s.io', kind: 'ClusterRole', name: p._metadata.name, }, subjects: [{ kind: 'ServiceAccount', name: p._metadata.name, namespace: p._config.namespace, }], }, roleSpecificNamespaces: local newSpecificRole(namespace) = { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'Role', metadata: p._metadata { namespace: namespace, }, rules: [ { apiGroups: [''], resources: ['services', 'endpoints', 'pods'], verbs: ['get', 'list', 'watch'], }, { apiGroups: ['extensions'], resources: ['ingresses'], verbs: ['get', 'list', 'watch'], }, { apiGroups: ['networking.k8s.io'], resources: ['ingresses'], verbs: ['get', 'list', 'watch'], }, ], }; { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'RoleList', items: [newSpecificRole(x) for x in p._config.namespaces], }, [if (defaults + params).replicas > 1 then 'podDisruptionBudget']: { apiVersion: 'policy/v1', kind: 'PodDisruptionBudget', metadata: p._metadata, spec: { minAvailable: 1, selector: { matchLabels: p._config.selectorLabels, }, }, }, prometheus: { apiVersion: 'monitoring.coreos.com/v1', kind: 'Prometheus', metadata: p._metadata { name: p._config.name, }, spec: { replicas: p._config.replicas, version: p._config.version, image: p._config.image, podMetadata: { labels: p.prometheus.metadata.labels, }, externalLabels: p._config.externalLabels, enableFeatures: p._config.enableFeatures, serviceAccountName: p.serviceAccount.metadata.name, podMonitorSelector: {}, podMonitorNamespaceSelector: {}, probeSelector: {}, probeNamespaceSelector: {}, ruleNamespaceSelector: {}, ruleSelector: p._config.ruleSelector, serviceMonitorSelector: {}, serviceMonitorNamespaceSelector: {}, nodeSelector: { 'kubernetes.io/os': 'linux' }, resources: p._config.resources, alerting: if p._config.alerting != {} then p._config.alerting else { alertmanagers: [{ namespace: p._config.namespace, name: 'alertmanager-' + p._config.alertmanagerName, port: 'web', apiVersion: 'v2', }], }, securityContext: { runAsUser: 1000, runAsNonRoot: true, fsGroup: 2000, }, [if std.objectHas(params, 'thanos') then 'thanos']: p._config.thanos, }, }, serviceMonitor: { apiVersion: 'monitoring.coreos.com/v1', kind: 'ServiceMonitor', metadata: p._metadata, spec: { selector: { matchLabels: p._config.selectorLabels, }, endpoints: [ { port: 'web', interval: '30s' }, { port: 'reloader-web', interval: '30s' }, ], }, }, // Include thanos sidecar PrometheusRule only if thanos config was passed by user [if std.objectHas(params, 'thanos') && params.thanos != null then 'prometheusRuleThanosSidecar']: { apiVersion: 'monitoring.coreos.com/v1', kind: 'PrometheusRule', metadata: p._metadata { labels+: p._config.mixin.ruleLabels, name: p._metadata.name + '-thanos-sidecar-rules', }, spec: { local r = if std.objectHasAll(p.mixinThanos, 'prometheusRules') then p.mixinThanos.prometheusRules.groups else [], local a = if std.objectHasAll(p.mixinThanos, 'prometheusAlerts') then p.mixinThanos.prometheusAlerts.groups else [], groups: a + r, }, }, // Include thanos sidecar Service only if thanos config was passed by user [if std.objectHas(params, 'thanos') && params.thanos != null then 'serviceThanosSidecar']: { apiVersion: 'v1', kind: 'Service', metadata+: p._metadata { name: p._metadata.name + '-thanos-sidecar', labels+: { 'app.kubernetes.io/component': 'thanos-sidecar', }, }, spec+: { ports: [ { name: 'grpc', port: 10901, targetPort: 10901 }, { name: 'http', port: 10902, targetPort: 10902 }, ], selector: p._config.selectorLabels { 'app.kubernetes.io/component': 'prometheus', }, clusterIP: 'None', }, }, // Include thanos sidecar ServiceMonitor only if thanos config was passed by user [if std.objectHas(params, 'thanos') && params.thanos != null then 'serviceMonitorThanosSidecar']: { apiVersion: 'monitoring.coreos.com/v1', kind: 'ServiceMonitor', metadata+: p._metadata { name: 'thanos-sidecar', labels+: { 'app.kubernetes.io/component': 'thanos-sidecar', }, }, spec+: { jobLabel: 'app.kubernetes.io/component', selector: { matchLabels: { 'app.kubernetes.io/component': 'thanos-sidecar', }, }, endpoints: [{ port: 'http', interval: '30s', }], }, }, }